news 2026/9/23 11:15:32

Yii 2 配置(Configuration)机制完全指南:从配置数组到依赖注入容器与默认配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Yii 2 配置(Configuration)机制完全指南:从配置数组到依赖注入容器与默认配置
  • 后端
  • Web框架

【免费下载链接】yii2

Yii 2: The Fast, Secure and Professional PHP Framework

项目地址:https://gitcode.com/gh_mirrors/yi/yii2
点击查看免费下载

Yii 2 在创建新对象或初始化既有对象时,广泛使用"配置信息(configuration)"这一机制。本文以官方指南 docs/guide-ja/concept-configurations.md 为骨架,结合仓库中framework/BaseYii.phpframework/di/Container.phpframework/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', // ... 行为属性初始值 ... ], ]

底层是如何识别onas前缀的

配置之所以能支持事件与行为,关键在于 framework/base/Component.php 的__set()魔术方法。当通过配置给组件赋值时,它按以下顺序处理:

  1. 若存在set开头的 setter 方法,则作为属性赋值;
  2. 若键名以on开头,则调用$this->on(trim(substr($name, 3)), $value)附加事件处理器
  3. 若键名以as开头,则解析行为配置(支持行为实例、闭包、带class/__class的配置数组或行为类名字符串),并调用attachBehavior()附加行为
  4. 否则回退为给已附加行为的同名属性赋值。

因此,只有当对象是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 在构造函数中会把核心组件与自定义组件做一次合并:如果某个核心组件(如dbcache)没有出现在配置中,就使用默认配置;如果出现了但没写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' => [ // 依赖注入容器单例的配置 ] ] ];

definitionssingletons配置数组支持的值及其示例,可阅读依赖注入容器一节的"高级实际用法"。在 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 个。不使用默认配置的话,你就必须在每个使用分页器的地方手动设置maxButtonCountmaxButtonCount的默认值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_PRODtrue。未特别定义时,这是YII_ENV默认值
dev开发环境。常量YII_ENV_DEVtrue
test测试环境。常量YII_ENV_TESTtrue

这些环境常量由 framework/BaseYii.php 在框架加载时统一计算并定义:YII_ENV默认prodYII_ENV_PROD/YII_ENV_DEV/YII_ENV_TEST则分别由YII_ENV === 'prod'(或devtest)推导而来。注意:这里YII_ENV的值不限于这三者,你完全可以定义staging等其他值(此时三个YII_ENV_*布尔常量均为false,可在配置中自行判断)。

利用环境常量,可以根据当前环境条件式地定制配置。例如,在开发环境启用调试工具栏与调试器时,应用配置可包含如下代码:

$config = [...]; if (YII_ENV_DEV) { // 为 'dev' 环境调整配置 $config['bootstrap'][] = 'debug'; $config['modules']['debug'] = 'yii\debug\Module'; } return $config;

小结与实践建议

回顾本文核心要点:

  1. 配置数组是 Yii 2 创建/初始化对象的标准手段,包含class、属性值、on 事件as 行为四类元素;
  2. Yii::createObject()(内部走 DI 容器)负责"按配置创建对象",Yii::configure()负责"按配置初始化已有对象";
  3. 应用配置组件配置是配置最典型的两大场景,前者通过components批量注册组件,2.0.11 起还支持通过container配置 DI 容器;
  4. 复杂配置应拆分为多个配置文件,用require组合,便于维护;
  5. 通过Yii::$container->set()注册的默认配置可以对一类对象统一生效;
  6. 利用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

项目地址:https://gitcode.com/gh_mirrors/yi/yii2
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 11:14:35

Selenium自动化健康打卡实战:从脚本到通用填报框架

简介:这是一份面向高校学生与Python自动化爱好者的实战项目源码,基于Selenium实现浙江大学自动健康打卡功能,适合作为毕业设计、课程设计或自动化脚本学习案例。压缩包共10个文件,约6.91MB,以py脚本为核心,…

作者头像 李华
网站建设 2026/9/23 11:14:26

GitHub 周榜观察:DLSS 工具、AI 工作流与轻量应用成主流

GitHub 周榜趋势速报是我每周固定会看的东西。以前看热闹,现在看门道——星标暴涨不一定是项目真的好,可能只是踩中了某个情绪节点;星标涨得慢的项目,反而可能是闷声发大财的基建工具。2026-09-19 这一期榜单,整体给我…

作者头像 李华
网站建设 2026/9/23 11:10:39

电子秤设计核心链路:从应变片到ADC的模拟前端与标定

简介:这份资源面向电子信息、自动化及相关专业的课程设计学习者,提供一套基于电阻应变式传感器的2kg手提电子秤完整设计方案,帮助读者理解从重量信号采集到数字显示的整条测量链路。压缩包内共1个doc文档,约91KB,以文字…

作者头像 李华
网站建设 2026/9/23 11:08:02

NiFi 1.21.0 实现 MySQL 单表增量同步最佳实践

简介:本资源是一套基于Apache NiFi 1.21.0实现的MySQL到MySQL单表增量同步实战模板,面向大数据开发工程师、ETL工程师及NiFi初学者,解决CDC场景下日期字段解析、空值兼容性处理与SQL动态拼接等典型痛点。压缩包为8KB的ZIP文件,内含…

作者头像 李华
网站建设 2026/9/23 11:05:04

146、MLIR的Bfloat16与FP8等低精度格式支持

MLIR的Bfloat16与FP8等低精度格式支持 从一次诡异的精度损失调试说起 去年做AI推理引擎时,遇到一个让人抓狂的bug:模型在GPU上跑得好好的,换到某款AI加速芯片上,精度直接崩了。排查了三天,最后发现是MLIR的TypeConverter在把F32转成Bfloat16时,悄悄把某些中间结果的精度…

作者头像 李华