- 后端
- Web框架
【免费下载链接】yii2
Yii 2: The Fast, Secure and Professional PHP Framework
Yii 2 在创建新对象或初始化既有对象时,广泛使用"配置信息(configuration)"这一机制。本文以官方指南 docs/guide-ja/concept-configurations.md 为骨架,结合仓库中framework/BaseYii.php、framework/di/Container.php、framework/base/Component.php等源码实现,系统讲解配置数组的格式、Yii::createObject()与Yii::configure()的工作方式、应用与组件配置、配置文件拆分、默认配置以及YII_ENV环境常量的实战用法。读完本文,你将能够熟练运用配置数组创建与定制任意对象,并为你的应用搭建按环境切换的配置体系。
配置信息是什么
在 Yii 2 中,配置信息(configuration)通常是一个 PHP 数组,用于在创建新对象或初始化已有对象时指定:
- 要创建的对象的类名;
- 赋给对象属性(properties)的初始值列表;
- 附加到对象事件(events)上的事件处理器列表;
- 附加到对象上的行为(behaviors)列表。
最典型的用法是创建并初始化一个数据库连接:
$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()接收配置数组,实例化数组中class指定的类,然后使用配置数组的其余部分完成对象属性、事件处理器和行为的初始化。
如果对象已经存在,可以使用Yii::configure()用配置数组初始化对象的属性:
Yii::configure($object, $config);注意:此时配置数组中不能包含class元素。
源码层面的实现
在 framework/BaseYii.php 中,createObject()的实现逻辑如下:
public static function createObject($type, array $params = []) { if (is_string($type)) { return static::$container->get($type, $params); } if (is_callable($type, true)) { return static::$container->invoke($type, $params); } if (!is_array($type)) { throw new InvalidConfigException('Unsupported configuration type: ' . gettype($type)); } if (isset($type['__class'])) { $class = $type['__class']; unset($type['__class'], $type['class']); return static::$container->get($class, $params, $type); } if (isset($type['class'])) { $class = $type['class']; unset($type['class']); return static::$container->get($class, $params, $type); } throw new InvalidConfigException('Object configuration must be an array containing a "class" or "__class" element.'); }可见它支持三种入参形式:
- 类名字符串:直接交给
$container->get()创建实例; - 配置数组:要求包含
class(或__class)元素,其余键值对作为对象配置传入; - PHP 可调用对象(callable):交由
$container->invoke()执行。
当传入空数组或不支持的null时,会抛出yii\base\InvalidConfigException。这一点在测试 tests/framework/BaseYiiTest.php 中有明确断言。而 framework/BaseYii.php 中的configure()则更简单直接——它遍历配置数组,将每个键值对赋值给对象的同名属性:
public static function configure($object, $properties) { foreach ($properties as $name => $value) { $object->$name = $value; } return $object; }配置信息的格式
配置数组的正式格式可以描述如下:
[ 'class' => 'ClassName', 'propertyName' => 'propertyValue', 'on eventName' => $eventHandler, 'as behaviorName' => $behaviorConfig, ]其中各元素含义如下:
| 元素 | 含义 |
|---|---|
class | 要创建的对象的完整类名(fully qualified class name) |
propertyName | 指定名字的属性的初始值;键是属性名,值是对应的初始值。只有公共成员变量以及由 getter/setter 定义的属性才能被设置 |
on eventName | 指定将何种处理器附加到对象的事件上。数组键的格式是on后接事件名;处理器支持的格式详见事件一节 |
as behaviorName | 指定将何种行为附加到对象上。数组键格式是as后接行为名;$behaviorConfig的值本身又是一个配置数组,用来创建该行为 |
下面是一个同时包含初始属性值、事件处理器和行为配置的完整示例:
[ 'class' => 'app\components\SearchEngine', 'apiKey' => 'xxxxxxxx', 'on search' => function ($event) { Yii::info("Keyword searched: " . $event->keyword); }, 'as indexer' => [ 'class' => 'app\components\IndexerBehavior', // ... 行为属性初始值 ... ], ]底层是如何识别on与as前缀的
配置之所以能支持事件与行为,关键在于 framework/base/Component.php 的__set()魔术方法。当通过配置给组件赋值时,它按以下顺序处理:
- 若存在
set开头的 setter 方法,则作为属性赋值; - 若键名以
on开头,则调用$this->on(trim(substr($name, 3)), $value)附加事件处理器; - 若键名以
as开头,则解析行为配置(支持行为实例、闭包、带class/__class的配置数组或行为类名字符串),并调用attachBehavior()附加行为; - 否则回退为给已附加行为的同名属性赋值。
因此,只有当对象是yii\base\Component或其子类时,on ...与as ...语法才有效;而class与普通属性赋值则对所有对象通用。
配置信息的使用场景
配置信息在 Yii 的许多地方都会用到。开头已经展示了用Yii::createObject()按配置创建对象的方式,下面重点讲解两个最主要的用途:应用(Application)配置与组件(Component)配置。
应用配置
应用的配置信息可能是 Yii 中最复杂的数组之一,因为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\symfonymailer\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();关于应用components属性的详细配置,请参考应用与服务定位器两节。
从源码看,framework/base/Application.php 在构造函数中会把核心组件与自定义组件做一次合并:如果某个核心组件(如db、cache)没有出现在配置中,就使用默认配置;如果出现了但没写class,则自动补上核心组件的类名。这也是为什么配置中经常可以省略class的原因。
2.0.11 起支持在应用配置中定制依赖注入容器
从 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' => [ // 依赖注入容器单例的配置 ] ] ];definitions与singletons配置数组支持的值及其示例,可阅读依赖注入容器一节的"高级实际用法"。在 framework/base/Application.php 中,container键会先被取出并交给setContainer($config['container'])处理,随后从剩余配置中移除,因此它不会作为普通属性赋值。
组件(Widget)配置
使用组件(widget)时,通常需要借助配置数组来定制组件属性。yii\base\Widget::widget()与yii\base\Widget::begin()都接收配置数组。例如:
use yii\widgets\Menu; echo Menu::widget([ 'activateItems' => false, 'items' => [ ['label' => '主页', 'url' => ['site/index']], ['label' => '产品', 'url' => ['product/index']], ['label' => '登录', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest], ], ]);以上代码创建了一个Menu组件,将其activateItems属性初始化为false,并配置items属性以展示菜单项。由于类名已经由Menu::widget()给出,因此配置数组中不应再包含class键。
配置文件(Configuration Files)
当配置变得非常复杂时,通常的做法是把它放到一个或多个配置文件中。配置文件是一个返回配置数组的 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中通过require引入。components.php的内容大致如下:
return [ 'cache' => [ 'class' => 'yii\caching\FileCache', ], 'mailer' => [ 'class' => 'yii\symfonymailer\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();这种"按职责拆分 +require组合"的模式,是 Yii 项目中组织复杂配置的标准做法,也是后续按环境组合配置(见下文环境常量一节)的基础。
默认配置(Default Configurations)
Yii::createObject()基于依赖注入容器实现。因此,可以为一类对象指定所谓"默认配置(default configuration)",凡是经由Yii::createObject()创建的该类实例都会自动套用该配置。默认配置通常在引导(bootstrapping)阶段通过Yii::$container->set()注册:
\Yii::$container->set('yii\widgets\LinkPager', [ 'maxButtonCount' => 5, ]);上面的例子把所有链接分页器(yii\widgets\LinkPager)的页码按钮数从默认的 10 个调整为最多 5 个。不使用默认配置的话,你就必须在每个使用分页器的地方手动设置maxButtonCount。maxButtonCount的默认值10定义在 framework/widgets/LinkPager.php。
容器是如何实现默认配置的
在 framework/di/Container.php 中,set()把类的定义规范化后存入_definitions;当createObject()经由get()获取对象时,framework/di/Container.php 会取出该定义,把其中的配置与调用方传入的配置用array_merge合并(调用方的配置优先级更高),再执行构建。这意味着:
- 通过
Yii::$container->set()注册的默认配置会对所有该类的实例生效; - 具体某次调用传入的配置可以覆盖默认值;
set()还支持注册"别名"、接口绑定以及构造参数($params),容器会利用反射解析构造函数依赖并自动注入(见 framework/di/Container.php 的build()方法)。
对象的生命周期
配置如何生效还与对象的构造方式有关。framework/base/BaseObject.php 的构造函数揭示了 Yii 对象的初始化顺序:
public function __construct($config = []) { if (!empty($config)) { Yii::configure($this, $config); } $this->init(); }即:先执行构造函数 → 按配置初始化属性 → 调用init()方法。文档建议所有需要额外初始化的逻辑写在init()中,因为此时配置已经应用完毕。而 framework/base/Application.php 中应用的init()会触发bootstrap(),从而加载扩展并启动引导组件——这正是Yii::$container->set()这类默认配置注册代码的典型执行时机。
环境常量(Environment Constants)
配置往往随应用运行环境而变化。例如,开发环境使用名为mydb_dev的数据库,而生产服务器上使用mydb_prod。为了便于切换环境,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 |
这些环境常量由 framework/BaseYii.php 在框架加载时统一计算并定义:YII_ENV默认prod,YII_ENV_PROD/YII_ENV_DEV/YII_ENV_TEST则分别由YII_ENV === 'prod'(或dev、test)推导而来。注意:这里YII_ENV的值不限于这三者,你完全可以定义staging等其他值(此时三个YII_ENV_*布尔常量均为false,可在配置中自行判断)。
利用环境常量,可以根据当前环境条件式地定制配置。例如,在开发环境启用调试工具栏与调试器时,应用配置可包含如下代码:
$config = [...]; if (YII_ENV_DEV) { // 为 'dev' 环境调整配置 $config['bootstrap'][] = 'debug'; $config['modules']['debug'] = 'yii\debug\Module'; } return $config;小结与实践建议
回顾本文核心要点:
- 配置数组是 Yii 2 创建/初始化对象的标准手段,包含
class、属性值、on 事件、as 行为四类元素; Yii::createObject()(内部走 DI 容器)负责"按配置创建对象",Yii::configure()负责"按配置初始化已有对象";- 应用配置与组件配置是配置最典型的两大场景,前者通过
components批量注册组件,2.0.11 起还支持通过container配置 DI 容器; - 复杂配置应拆分为多个配置文件,用
require组合,便于维护; - 通过
Yii::$container->set()注册的默认配置可以对一类对象统一生效; - 利用
YII_ENV环境常量实现开发、测试、生产环境的条件化配置。
在动手实践时,建议从"配置文件拆分 + 环境常量组合 + 默认配置"三者入手构建你的应用配置体系:把公共配置放进common.php,把环境差异放进web.php/console.php,在入口脚本中按YII_ENV决定加载哪一套。相关实现细节与测试用例可分别参考 framework/di/Container.php、framework/base/BaseObject.php 与 tests/framework/BaseYiiTest.php。
- 后端
- Web框架
【免费下载链接】yii2
Yii 2: The Fast, Secure and Professional PHP Framework
相关推荐
Yii 2 配置(Configuration)完全指南:配置格式、应用与 Widget 配置、默认配置及多环境管理
Yii 2 配置(Configuration)完全指南:配置格式、应用与 Widget 配置、默认配置及多环境管理 配置(Configuration)在 Yii
后端Web框架Yii 2 依赖注入容器(DI Container)完全指南:从四种注入方式到实战配置
Yii 2 依赖注入容器(DI Container)完全指南:从四种注入方式到实战配置 导读 依赖注入容器(Dependency Injection Conta
后端Web框架Yii 2 配置机制完全指南:配置格式、应用与组件配置、默认配置及 YII_ENV 环境切换
Yii 2 配置机制完全指南:配置格式、应用与组件配置、默认配置及 YII_ENV 环境切换 Yii 2 框架中,配置(Configuration)是创建对象、
后端Web框架
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考