在Yii中創建新物件或初始化已經存在的物件廣泛的使用配置,配置通常包含被創建物件的類別名稱和一組將要賦值給物件的屬性的初始值,這裡的屬性是Yii2的屬性。也可以在物件的事件上綁定事件處理器,或將行為附加到物件上。從而在定義了物件的初始值的同時,充分規定物件的運行時的動態特性。
以下程式碼中的設定被用來建立並初始化一個資料庫連線:
$config = [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=127.0.0.1;dbname=demo', 'username' => 'root', 'password' => '', 'charset' => 'utf8', ];$db = Yii::createObject($config);
Yii::createObject()
是Yii2中最常用的用來創建對象的方法,其內容是從DI Container中去取的對象,在後面的章節中我們會講到。這個方法方法接受一個配置數組並根據數組中指定的類名創建對象,對象實例化後,剩餘的參數被用來初始化對象的屬性,事件和行為。
小編提醒:在Yii2.1中,配置陣列中用來表示類別名稱的鍵值由
class
變成了__class
,但是配置的原理是不變的。
對於已存在的對象,可以使用Yii::configure() 方法根據配置去初始化其屬性, 就像這樣:
Yii::configure($object, $config);
請注意,如果配置一個已存在的對象,那麼配置數組中不應該包含指定類別名稱的class 元素。
在程式設計中,有個非常重要的概念叫“委託”,就是一個物件A可以依靠另一個物件B去完成特定的功能,典型的應用就是策略模式了。要實現“委託”,要有這麼個流程:在物件A實例化時注入另一個物件B;A持有物件B;物件A委託物件B去完成特定的功能。 「注入」「持有」「委託」都是設計模式中的高頻詞彙,透過這些操作可以擴展類別的功能。
我們看看在別的物件導向語言如Java或PHP其他框架中常用的方式:
class Person { private $strategy = null; public function __construct(TravelStrategy $travel) { $this->strategy = $travel; } /** * 设置旅行的方式. */ public function setTravelStrategy(TravelStrategy $travel) { $this->strategy = $travel; } /** * 旅行. */ public function travel() { //这里实现了“委托”,委托给$this->strategy来实现旅行的具体方式 return $this->strategy->travelAlgorithm(); } }
在實例化或初始化時,大概就是這麼用的:
class Test{ public function run($argument) { // 乘坐火车旅行 $person = new Person(new TrainStrategy()); $person->travel(); // 改骑自行车 $person->setTravelStrategy(new BicycleStrategy()); $person->travel(); } }
Person
是一個想要旅行的人,它持有一個具體的交通方式類別$strategy
,最後旅遊就是委託給這個交通方式$strategy
來完成的-是騎車還是自駕遊還是搭飛機。在使用時先new 一個對象,並且在構造器裡面注入一種交通方式初始化旅行的方式,並且我還可以通過Person::setTravelStrategy
臨時決定改變旅行方式——這是策略模式的應用場景。
我們看看這一行:
$person = new Person(new TrainStrategy());
這種寫法大家再也熟悉不過了吧?其實這完成了兩步驟操作:
實例化物件Person,方式是new
#注入外部實例new TrainStrategy()
並對$person
初始化。注入的可以是實例當然也可以是常數。
但是按照Yii2的風格,就應該是這樣的:
class Person extends Component{ private $strategy = null; /** * 旅行. */ public function setTravelStrategy($travel) { if (!($travel instanceof TravelStrategy)) { $travel = Yii::createObject($travel); } $this->strategy = $travel; } /** * 旅行. */ public function travel() { return $this->strategy->travelAlgorithm(); } }
用法就大概是這樣的風格:
//用配置创建对象并初始化,选择火车出行 $person = Yii::createObject([ 'class' => Person::class, 'travelStrategy' => [ 'class' => TrainStrategy::class ] ]); $person->travel();//用配置重新初始化对象,改骑自行车 $person = Yii::configure($person, [ 'travelStrategy' => [ 'class' => BicycleStrategy::class ] ]); $person->travel();
上面這個例子,應該可以幫助大家了解Yii2配置的作用與使用方式。其中創建物件的方式不是透過new關鍵字,而是去依賴注入容器(DI Container)中去獲取的,後面我們會講到。
Yii2框架似乎不太喜歡用「通用」的實例化和初始化的方式,在Yii2框架內部幾乎都是透過配置來實現物件的實例化和初始化。這是Yii2的一個風格,當然這種風格看起來更為簡潔(前提是你已經熟悉),使用起來則是更為方便。雖說看起來有差異,但本質上還是一樣的,只是注入的方式有些差別罷了。
一個配置的格式可以描述為以下形式:
[ 'class' => 'ClassName', 'propertyName' => 'propertyValue', 'on eventName' => $eventHandler, 'as behaviorName' => $behaviorConfig, ]
其中,
class 元素指定了將要建立的物件的完整類別名稱(用Object::class就可以實作)
#propertyName 元素指定了物件可寫屬性的初始值
on eventName 元素指定了附加到物件事件上的處理器。 請注意,陣列的鍵名由 on 前綴加事件名組成。 on和事件名稱之間只能有一個空格
as behaviorName 元素指定了附加到物件的行為。 請注意,陣列的鍵名由 as 前綴加行為名組成。 as和行為名之間只能有一個空格。 $behaviorConfig
值表示創建行為的配置訊息,格式與我們之前描述的配置格式一樣。
下面是一個配置了初始化屬性值,事件處理器和行為的範例:
[ 'class' => 'app\components\SearchEngine', 'apiKey' => 'xxxxxxxx', 'on search' => function ($event) { Yii::info("搜索的关键词: " . $event->keyword); }, 'as indexer' => [ 'class' => 'app\components\IndexerBehavior', // ... 初始化属性值 ... ], ]
我們依照這樣的約定,就可以透過配置數組去是實例化和初始化物件:
實作Configurable接口,只要你繼承BaseObject或Component,這條都是滿足的-無須擔心
子类重载__construct
方法时,把配置数组放到构造器的最后一个参数:__construct($param1, $param2, ..., $config)
子类在自己的__construct
最后,必须调用parent::__construct($config)
方法
到底是如何实现的呢?这还得从BaseObject中说起,看看BaseObject的构造器:
public function __construct($config = []){ if (!empty($config)) { Yii::configure($this, $config); } $this->init(); }
我们知道Yii::configure
是实现配置的。我们如果每个子类的__construct
都按照上面的规范写,那么到最后无异会调用BaseObject::__construct
,并且将子类的配置数组$config也传递过来,最终被Yii::configure
使用。我们再看看这个方法:
// $object就是即将被配置的对象实例,$properties是配置数组public static function configure($object, $properties){ //遍历每个参数,将其设置为属性,这里可能调用setter等方法 foreach ($properties as $name => $value) { $object->$name = $value; } return $object; }
这一句$object->$name = $value
可能会发生很多故事,可能会调用Component::__setter
或者BaseObject::__setter
(参看我们前面讲属性,行为,事件的章节)
Yii 中的配置可以用在很多场景,除了我们上面举的例子,最常见的莫过于Yii最大的实例Application的配置了。Application堪称最复杂的配置之一了, 因为 Application 类拥有很多可配置的属性和事件。 更重要的是它的 yii\web\Application::components 属性也可以接收配置数组并通过应用注册为组件,配置中还可以有配置。 以下是一个针对基础应用模板的应用配置概要:
$config = [ 'id' => 'basic', 'basePath' => dirname(__DIR__), 'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), 'components' => [ 'cache' => [ 'class' => 'yii\caching\FileCache', ], 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', ], 'log' => [ 'class' => 'yii\log\Dispatcher', 'traceLevel' => YII_DEBUG ? 3 : 0, 'targets' => [ [ 'class' => 'yii\log\FileTarget', ], ], ], 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=stay2', 'username' => 'root', 'password' => '', 'charset' => 'utf8', ], ], ];
配置中没有 class 键的原因是这段配置应用在下面的入口脚本中, 类名已经指定了。
(new yii\web\Application($config))->run();
Application的配置中,比较重要的是components
属性的配置了。在components
里配置了的,都作为一个单例可以通过Yii::$app->component
来访问;
另外,自版本 2.0.11 开始,系统配置支持使用 container 属性来配置依赖注入容器 例如:
$config = [ 'id' => 'basic', 'basePath' => dirname(__DIR__), 'extensions' => require __DIR__ . '/../vendor/yiisoft/extensions.php', 'container' => [ 'definitions' => [ 'yii\widgets\LinkPager' => ['maxButtonCount' => 5] ], 'singletons' => [ // 依赖注入容器单例配置 ] ] ];
我们这里重点阐述的是配置的原理,并不对Application做过多的配置,只是加深下大家对配置用法的印象而已,关于Application的配置我们以后会有讲到。
当配置的内容十分复杂,通用做法是将其存储在一或多个 PHP 文件中, 这些文件被称为配置文件。一个配置文件返回的是 PHP 数组。 例如,像这样把应用配置信息存储在名为 web.php 的文件中:
return [ 'id' => 'basic', 'basePath' => dirname(__DIR__), 'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), 'components' => require(__DIR__ . '/components.php'), ];
鉴于 components 配置也很复杂,上述代码把它们存储在单独的 components.php 文件中,并且包含在 web.php 里。 components.php 的内容如下:
return [ 'cache' => [ 'class' => 'yii\caching\FileCache', ], 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', ], 'log' => [ 'class' => 'yii\log\Dispatcher', 'traceLevel' => YII_DEBUG ? 3 : 0, 'targets' => [ [ 'class' => 'yii\log\FileTarget', ], ], ], 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=stay2', 'username' => 'root', 'password' => '', 'charset' => 'utf8', ], ];
如果数据库配置复杂了,你也可以单独拿出来——总之,简洁易维护就行。
仅仅需要 “require”,就可以取得一个配置文件的配置内容,像这样:
$config = require('path/to/web.php');(new yii\web\Application($config))->run();
Yii::createObject() 方法基于依赖注入容器实现,你可以通过 Yii::creatObject() 创建对象时实现配置,同样也可以直接调用 Yii::$container->set() 来实现:
\Yii::$container->set('yii\widgets\LinkPager', [ 'maxButtonCount' => 5, ]);
配置经常会随着环境的更改而更改,有哪些环境呢?——生产,开发,测试。不同的环境可能会提供不同的组件,因此我们可以先定义不同的环境变量。
为了便于切换使用环境,Yii 提供了一个定义在入口脚本中的 YII_ENV 常量。 如下:
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。
有了这些环境常量,你就可以根据当下应用运行环境的不同,进行差异化配置。 例如,应用可以包含下述代码只在开发环境中开启 调试工具。
$config = [...];if (YII_ENV_DEV) { // 根据 `dev` 环境进行的配置调整 $config['bootstrap'][] = 'debug'; $config['modules']['debug'] = 'yii\debug\Module'; }return $config;
关于配置的东西,大概就是这么多了。
以上是Yii2配置基本概念的詳細內容。更多資訊請關注PHP中文網其他相關文章!