組態


組態

在 Yii 中,建立新物件和初始化已存在物件時廣泛使用組態。組態通常包含被建立物件的類名和一組將要賦值給物件屬性的初始值。還可能包含一組將被附加到物件事件上的控制代碼。和一組將被附加到物件上的行為

以下程式碼中的組態被用來建立並初始化一個資料庫連線:

  1. $config = [ 
  2.     'class' => 'yii\\db\\Connection', 
  3.     'dsn' => 'mysql:host=127.0.0.1;dbname=demo', 
  4.     'username' => 'root', 
  5.     'password' => '', 
  6.     'charset' => 'utf8', 
  7. ]; 
  8.  
  9. $db = Yii::createObject($config);

[[Yii::createObject()]] 方法接受一個組態並根據組態中指定的類名建立物件。物件範例化後,剩餘的引數被用來初始化物件的屬性,事件處理和行為。

對於已存在的物件,可以使用 [[Yii::configure()]] 方法根據組態去初始化其屬性,就像這樣:

  1. Yii::configure($object, $config);

請注意,如果組態一個已存在的物件,那麼組態陣列中不應該包含指定類名的 class 元素。

組態的格式

一個組態的格式可以描述為以下形式:

  1.     'class' => 'ClassName', 
  2.     'propertyName' => 'propertyValue', 
  3.     'on eventName' => $eventHandler, 
  4.     'as behaviorName' => $behaviorConfig, 
  5. ]

其中

  • class 元素指定了將要建立的物件的完全限定類名。
  • propertyName 元素指定了物件屬性的初始值。鍵名是屬性名,值是該屬性對應的初始值。只有公共成員變數以及通過 getter/setter 定義的屬性可以被組態。
  • on eventName 元素指定了附加到物件事件上的控制代碼是什麼。請注意,陣列的鍵名由 on 字首加事件名組成。請參考事件章節了解事件控制代碼格式。
  • as behaviorName 元素指定了附加到物件的行為。請注意,陣列的鍵名由 as 字首加行為名組成。$behaviorConfig 表示建立行為的組態資訊,格式與我們現在總體敘述的組態格式一樣。

下面是一個組態了初始化屬性值,事件控制代碼和行為的範例:

  1.     'class' => 'app\\components\\SearchEngine', 
  2.     'apiKey' => 'xxxxxxxx', 
  3.     'on search' => function ($event) { 
  4.         Yii::info("搜尋的關鍵詞: " . $event->keyword); 
  5.     }, 
  6.     'as indexer' => [ 
  7.         'class' => 'app\\components\\IndexerBehavior', 
  8.         // ... 初始化屬性值 ... 
  9.     ], 
  10. ]

使用組態

Yii 中的組態可以用在很多場景。本章開頭我們展示了如何使用 [[Yii::creatObject()]] 根據組態資訊建立物件。本小節將介紹組態的兩種主要用法 —— 組態應用與組態小部件。

應用的組態

應用的組態可能是最複雜的組態之一。因為 [[yii\web\Application|application]] 類擁有很多可組態的屬性和事件。更重要的是它的 [[yii\web\Application::components|components]] 屬性可以接收組態陣列並通過應用註冊為元件。以下是一個針對基礎應用模板的應用組態概要:

  1. $config = [ 
  2.     'id' => 'basic', 
  3.     'basePath' => dirname(__DIR__), 
  4.     'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), 
  5.     'components' => [ 
  6.         'cache' => [ 
  7.             'class' => 'yii\\caching\\FileCache', 
  8.         ], 
  9.         'mailer' => [ 
  10.             'class' => 'yii\\swiftmailer\\Mailer', 
  11.         ], 
  12.         'log' => [ 
  13.             'class' => 'yii\\log\\Dispatcher', 
  14.             'traceLevel' => YII_DEBUG ? 3 : 0, 
  15.             'targets' => [ 
  16.                 [ 
  17.                     'class' => 'yii\\log\\FileTarget', 
  18.                 ], 
  19.             ], 
  20.         ], 
  21.         'db' => [ 
  22.             'class' => 'yii\\db\\Connection', 
  23.             'dsn' => 'mysql:host=localhost;dbname=stay2', 
  24.             'username' => 'root', 
  25.             'password' => '', 
  26.             'charset' => 'utf8', 
  27.         ], 
  28.     ], 
  29. ];

組態中沒有 class 鍵的原因是這段組態應用在下面的入口指令碼中,類名已經指定了。

  1. (new yii\\web\\Application($config))->run();

更多關於應用 components 屬性組態的資訊可以查閱應用以及服務定位器章節。

小部件的組態

使用小部件時,常常需要組態以便自定義其屬性。 [[yii\base\Widget::widget()]] 和 [[yii\base\Widget::beginWidget()]] 方法都可以用來建立小部件。它們可以接受組態陣列:

  1. use yii\\widgets\\Menu; 
  2.  
  3. echo Menu::widget([ 
  4.     'activateItems' => false, 
  5.     'items' => [ 
  6.         ['label' => 'Home', 'url' => ['site/index']], 
  7.         ['label' => 'Products', 'url' => ['product/index']], 
  8.         ['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest], 
  9.     ], 
  10. ]);

上述程式碼建立了一個小部件 Menu 並將其 activateItems 屬性初始化為 false。item 屬性也組態成了將要顯示的選單條目。

請注意,程式碼中已經給出了類名 yii\widgets\Menu',組態陣列**不應該**再包含 class` 鍵。

組態檔案

當組態的內容十分複雜,通用做法是將其儲存在一或多個 PHP 檔案中,這些檔案被稱為組態檔案。一個組態檔案返回的是 PHP 陣列。例如,像這樣把應用組態資訊儲存在名為 web.php 的檔案中:

  1. return [ 
  2.     'id' => 'basic', 
  3.     'basePath' => dirname(__DIR__), 
  4.     'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), 
  5.     'components' => require(__DIR__ . '/components.php'), 
  6. ];

鑑於 components 組態也很複雜,上述程式碼把它們儲存在單獨的 components.php 檔案中,並且包含在web.php 裡。components.php 的內容如下:

  1. return [ 
  2.     'cache' => [ 
  3.         'class' => 'yii\\caching\\FileCache', 
  4.     ], 
  5.     'mailer' => [ 
  6.         'class' => 'yii\\swiftmailer\\Mailer', 
  7.     ], 
  8.     'log' => [ 
  9.         'class' => 'yii\\log\\Dispatcher', 
  10.         'traceLevel' => YII_DEBUG ? 3 : 0, 
  11.         'targets' => [ 
  12.             [ 
  13.                 'class' => 'yii\\log\\FileTarget', 
  14.             ], 
  15.         ], 
  16.     ], 
  17.     'db' => [ 
  18.         'class' => 'yii\\db\\Connection', 
  19.         'dsn' => 'mysql:host=localhost;dbname=stay2', 
  20.         'username' => 'root', 
  21.         'password' => '', 
  22.         'charset' => 'utf8', 
  23.     ], 
  24. ];

僅僅需要 “require”,就可以取得一個組態檔案的組態內容,像這樣:

  1. $config = require('path/to/web.php'); 
  2. (new yii\\web\\Application($config))->run();

預設組態

[[Yii::createObject()]] 方法基於依賴注入容器實現。使用 [[Yii::creatObject()]] 建立物件時,可以附加一系列預設組態到指定類的任何範例。預設組態還可以在入口指令碼中呼叫 Yii::$container->set() 來定義。

例如,如果你想自定義 [[yii\widgets\LinkPager]] 小部件,以便讓分頁器最多只顯示 5 個翻頁按鈕(預設是 10 個),你可以用下述程式碼實現:

  1. \\Yii::$container->set('yii\\widgets\\LinkPager', [ 
  2.     'maxButtonCount' => 5, 
  3. ]);

不使用預設組態的話,你就得在任何使用分頁器的地方,都組態 maxButtonCount 的值。

環境常數

組態經常要隨著應用執行的不同環境更改。例如在開發環境中,你可能使用名為 mydb_dev 的資料庫,而生產環境則使用 mydb_prod 資料庫。為了便於切換使用環境,Yii 提供了一個定義在入口指令碼中的 YII_ENV 常數。如下:

  1. defined('YII_ENV') or define('YII_ENV', 'dev');

你可以把 YII_ENV 定義成以下任何一種值:

  • prod:生產環境。常數 YII_ENV_PROD 將被看作 true。如果你沒修改過,這就是 YII_ENV 的預設值。
  • dev:開發環境。常數 YII_ENV_DEV 將被看作 true。
  • test:測試環境。常數 YII_ENV_TEST 將被看作 true。

有了這些環境常數,你就可以根據當下應用執行環境的不同,進行差異化組態。例如,應用可以包含下述程式碼只在開發環境中開啟偵錯工具

  1. $config = [...]; 
  2.  
  3. if (YII_ENV_DEV) { 
  4.     // 根據 `dev` 環境進行的組態調整 
  5.     $config['bootstrap'][] = 'debug'; 
  6.     $config['modules']['debug'] = 'yii\\debug\\Module'; 
  7.  
  8. return $config;