구성은 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에서 객체를 생성하는 데 가장 일반적으로 사용되는 방법이며 그 내용은 다음과 같습니다. is 우리는 이후 장에서 DI 컨테이너에서 검색된 객체에 대해 이야기할 것입니다. 이 메서드는 구성 배열을 받아들이고 배열에 지정된 클래스 이름을 기반으로 개체를 생성합니다. 개체가 인스턴스화되면 나머지 매개 변수는 개체의 속성, 이벤트 및 동작을 초기화하는 데 사용됩니다. 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
편집자 알림: Yii2.1에서는 구성 배열의 클래스 이름을 나타내는 데 사용되는 키 값이class
에서__class
로 변경되었지만 구성은 원칙은 변함이 없습니다.
[ 'class' => 'app\components\SearchEngine', 'apiKey' => 'xxxxxxxx', 'on search' => function ($event) { Yii::info("搜索的关键词: " . $event->keyword); }, 'as indexer' => [ 'class' => 'app\components\IndexerBehavior', // ... 初始化属性值 ... ], ]
public function __construct($config = []){ if (!empty($config)) { Yii::configure($this, $config); } $this->init(); }
// $object就是即将被配置的对象实例,$properties是配置数组public static function configure($object, $properties){ //遍历每个参数,将其设置为属性,这里可能调用setter等方法 foreach ($properties as $name => $value) { $object->$name = $value; } return $object; }
사람
여행을 하고 싶은 사람이며, 특정 교통수단 클래스 $strategy
를 보유하고 있으며 최종 여행은 이 교통수단 $strategy
에 맡깁니다. 완료하려면 - 예 자전거 타기, 자동차 여행 또는 비행기 여행. 사용할 때 먼저 새 객체를 생성하고 생성자에 교통 수단을 주입하여 이동 방법을 초기화하고, Person::setTravelStrategy
를 통해 일시적으로 이동 방법을 변경하도록 결정할 수도 있습니다. 전략 패턴 적용 시나리오. 🎜🎜이 줄을 살펴 보겠습니다. 🎜$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', ], ], ];
$person
을 초기화하여 Person 객체를 인스턴스화합니다. 주입되는 것은 인스턴스일 수도 있고 상수일 수도 있습니다. 🎜🎜🎜🎜하지만 Yii2의 스타일에 따르면 다음과 같아야 합니다: 🎜(new yii\web\Application($config))->run();
$config = [ 'id' => 'basic', 'basePath' => dirname(__DIR__), 'extensions' => require __DIR__ . '/../vendor/yiisoft/extensions.php', 'container' => [ 'definitions' => [ 'yii\widgets\LinkPager' => ['maxButtonCount' => 5] ], 'singletons' => [ // 依赖注入容器单例配置 ] ] ];
return [ 'id' => 'basic', 'basePath' => dirname(__DIR__), 'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), 'components' => require(__DIR__ . '/components.php'), ];
$behaviorConfig
값은 동작을 생성하기 위한 구성 정보를 나타내며 형식은 앞서 설명한 구성 형식과 동일합니다. 🎜🎜🎜🎜다음은 초기화 속성 값, 이벤트 핸들러 및 동작을 구성하는 예입니다. 🎜鉴于 components 配置也很复杂,上述代码把它们存储在单独的 components.php 文件中,并且包含在 web.php 里。 components.php 的内容如下:
子类重载__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 중국어 웹사이트의 기타 관련 기사를 참조하세요!