
Yii 2 配置系统完全指南创建对象、应用配置、默认配置与环境常量【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2配置Configuration是 Yii 2 框架最核心的基础设施之一无论是创建数据库连接、初始化应用组件还是定制小部件、挂载事件与行为都统一通过配置数组完成。本篇指南以 docs/guide-zh-CN/concept-configurations.md 为骨架结合框架源码framework/BaseYii.php、framework/di/Container.php、framework/base/Component.php深入讲解配置格式、Yii::createObject()与Yii::configure()的底层实现、应用与小部件配置、配置文件的组织方式、基于依赖注入容器的默认配置以及按环境切换配置的YII_ENV常量体系。读完本篇你将能熟练写出结构清晰、可维护、按环境差异化生效的 Yii 2 配置。什么是配置创建对象与初始化对象在 Yii 中创建新对象和初始化已存在对象时都会广泛使用配置。一个配置通常包含三部分信息被创建对象的类名一组将要赋值给对象属性的初始值可选的一组将被附加到对象事件上的事件句柄以及一组将被附加到对象上的行为。以下代码用配置创建并初始化一个数据库连接$config [ class yii\db\Connection, dsn mysql:host127.0.0.1;dbnamedemo, username root, password , charset utf8, ]; $db Yii::createObject($config);Yii::createObject()接受一个配置数组根据其中class元素指定的类名实例化对象对象创建完成后剩余参数被用于初始化属性、事件处理和行为。对于已存在的对象可以使用Yii::configure()方法依据配置去初始化其属性Yii::configure($object, $config);注意当配置用于初始化一个已存在的对象时配置数组中不应该再包含class元素否则会触发不必要的类解析逻辑。源码视角createObject 与 configure 的实现在 framework/BaseYii.php 中Yii::createObject()的静态实现体现了框架对配置类型的宽容处理传入字符串时视为类名直接交给static::$container-get($type, $params)由依赖注入容器解析传入**可调用对象callable**时使用static::$container-invoke()执行传入数组时读取其中的class键或__class键得到类名将其从配置中移除后把剩余配置作为$config参数传给Container::get()若数组缺少class/__class键则抛出InvalidConfigException提示对象配置必须是包含 class 或 __class 元素的数组。而Yii::configure()framework/BaseYii.php的实现非常朴素——遍历配置数组逐一执行$object-$name $value。赋值的落地效果取决于对象基类对于继承 framework/base/BaseObject.php 的普通对象__set()会优先调用对应的setXxx()方法若只有 getter 没有 setter 则视为只读属性抛出InvalidCallException两者皆无则抛出UnknownPropertyException。这一机制正是只有公共成员变量以及通过 getter/setter 定义的属性可以被配置这一规则的本质来源。配置的格式Configuration Format一个配置数组的完整格式可以描述为[ class ClassName, propertyName propertyValue, on eventName $eventHandler, as behaviorName $behaviorConfig, ]其中各元素的语义如下元素含义注意事项class将要创建对象的完全限定类名仅用于创建新对象配置已存在对象时须省略propertyName对象属性的初始值键名是属性名只有公共成员变量以及通过 getter/setter 定义的属性可被配置on eventName附加到对象事件上的句柄键名由on前缀 事件名组成事件句柄格式见事件章节as behaviorName附加到对象的行为键名由as前缀 行为名组成$behaviorConfig是创建行为的配置格式与普通配置相同下面是一个同时配置了属性初值、事件句柄和行为的完整示例[ class app\components\SearchEngine, apiKey xxxxxxxx, on search function ($event) { Yii::info(搜索的关键词 . $event-keyword); }, as indexer [ class app\components\IndexerBehavior, // ... 初始化属性值 ... ], ]源码视角on 与 as 前缀如何被解析on与as前缀并不是配置数组的魔法语法而是由组件基类的__set()魔术方法在赋值阶段分流的。framework/base/Component.php 中__set()的判定顺序为存在setXxx()setter → 走属性赋值键名以on开头前 3 个字符→ 截取eventName并调用$this-on(trim(substr($name, 3)), $value)绑定事件处理器on()的实现见 framework/base/Component.php支持通配符事件与追加/前置两种挂载策略键名以as开头 → 截取行为名并根据值类型决定如何创建行为Behavior实例直接附加Closure调用闭包得到行为实例配置数组或类名字符串通过Yii::createObject()创建并校验其确实是Behavior的子类否则抛出InvalidConfigException。最终统一交由attachBehavior()framework/base/Component.php挂载。这也解释了为什么行为值既可以是对象、配置数组也可以是行为类名的字符串——__set()对这三种形态都做了兼容。使用配置Using Configurations配置在 Yii 中几乎无处不在最常见的两大使用场景是配置应用与配置小部件。应用的配置Application Configurations应用的配置可能是最复杂的一类配置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:hostlocalhost;dbnamestay2, username root, password , charset utf8, ], ], ];注意此配置中没有class键因为应用类名已在入口脚本中显式指定(new yii\web\Application($config))-run();这种入口脚本给类名、配置数组给属性的分工正对应前面提到的规则已知类名时配置不再需要class元素。自版本 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定义单例类——两者最终都会注册进容器使后续Yii::createObject()创建的对象自动应用这些规则。更完整的definitions与singletons用法参见依赖注入容器章节下的高级应用实例。小部件的配置Widget Configurations使用小部件时通常需要传入配置以自定义其属性。yii\base\Widget::widget()和yii\base\Widget::begin()都可以接受配置数组use yii\widgets\Menu; echo Menu::widget([ activateItems false, items [ [label Home, url [site/index]], [label Products, url [product/index]], [label Login, url [site/login], visible Yii::$app-user-isGuest], ], ]);上述代码创建了一个yii\widgets\Menu小部件将其activateItems属性初始化为falseitems属性配置为要渲染的菜单项。请注意代码中已经写出了类名yii\widgets\Menu配置数组不应再包含class键。Menu::widget()内部正是通过Yii::createObject()或new static()Yii::configure()把这段配置应用到小部件实例上的。配置文件Configuration Files当配置内容十分复杂时通用做法是把配置存储在一个或多个 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中再通过require合并进web.phpreturn [ 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:hostlocalhost;dbnamestay2, username root, password , charset utf8, ], ];在入口脚本中只需一条require即可取得配置内容并启动应用$config require path/to/web.php; (new yii\web\Application($config))-run();这种按职责拆分 require 合并的组织方式是 Yii 2 高级模板advanced template多环境、多入口配置管理的基础例如common/config/main.php与console/config/main.php分别面向 Web 与控制台入口复用同一套组件配置。默认配置Default ConfigurationsYii::createObject()基于依赖注入容器实现。因此你可以在入口脚本中调用Yii::$container-set()给指定类的所有实例附加一系列默认配置之后每次通过Yii::createObject()创建该类的对象时默认配置都会自动合并生效。例如想让分页器小部件yii\widgets\LinkPager最多只显示 5 个翻页按钮默认是 10 个只需在入口脚本中写\Yii::$container-set(yii\widgets\LinkPager, [ maxButtonCount 5, ]);不使用默认配置的话你就不得不在每个使用分页器的地方重复配置maxButtonCount的值。源码视角set 与 setSingleton 的注册机制Container::set()framework/di/Container.php将规范化后的类定义存入_definitions并清除已有的单例缓存Container::setSingleton()framework/di/Container.php与之类似但额外标记为单例——后续每次get()都返回同一实例。当Yii::createObject()携带配置调用Container::get()时framework/di/Container.php若该类注册过 definition且 definition 是数组框架会先取出class键得到具体类把 definition 的其余部分与本次调用传入的$config通过array_merge合并调用侧配置优先再进入构建流程构建过程由build()framework/di/Container.php完成通过反射解析构造函数依赖、合并构造参数最终若对象实现了yii\base\Configurable接口则将配置作为构造函数最后一个参数传入否则在new之后逐一对$object-$name $value赋值。也就是说默认配置之所以能作用于所有LinkPager实例正是因为widgets内部创建小部件时统一走Yii::createObject()而容器在构建阶段把注册的 definition 与调用侧配置做了合并。该行为的自动化验证可参见 tests/framework/di/ContainerTest.php 中关于依赖与定义解析的测试用例。环境常量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的默认值就是proddev开发环境YII_ENV_DEV为truetest测试环境YII_ENV_TEST为true有了这些环境常量就可以针对当前运行环境做差异化配置。例如只在开发环境中启用调试工具模块$config [...]; if (YII_ENV_DEV) { // 根据 dev 环境进行的配置调整 $config[bootstrap][] debug; $config[modules][debug] yii\debug\Module; } return $config;源码视角环境常量的派生规则在 framework/BaseYii.php 中框架用defined(YII_ENV) or define(YII_ENV, prod)兜底默认值为prod再根据YII_ENV的具体取值派生出三个布尔常量YII_ENV_PROD⇔YII_ENV prodYII_ENV_DEV⇔YII_ENV devYII_ENV_TEST⇔YII_ENV test因此入口脚本只需在vendor/autoload.php加载、框架文件被执行之前即BaseYii.php首次加载之前定义好YII_ENV整个应用便能据此切换数据库、日志、缓存乃至调试模块。生产环境部署时若不做任何定义YII_ENV也会自动回落到prod保证安全默认。进阶技巧与常见误区配置对象时的class键取舍Yii::createObject()创建新对象必须提供class或__classYii::configure()与已知类名的小部件配置则绝不能带class否则容器会重新解析类名并可能覆盖你的实例。属性赋值走 setter 而非直接写字段由于__set()优先调用setXxx()配置数组的键名可以与公共属性名不同例如配置onRequest时实际调用setOnRequest()同时只读属性只有 getter会抛异常配置前请先确认属性可写。on/as键名必须保留前缀与空格on search不是onsearch前缀解析依赖strncmp($name, on , 3)这类精确匹配。默认配置与 DI 容器配置合并顺序注册在容器的 definition 先合并调用侧传入的配置数组后合并、优先级更高可用于对默认配置做局部覆盖。多环境配置文件组织可结合按职责拆分main/params/console 按环境覆盖web.php与web-local.php、YII_ENV条件分支的组合方式实现与高级模板一致的环境隔离。总结配置是 Yii 2 一切对象创建与初始化的统一入口Yii::createObject()负责按配置建对象Yii::configure()负责按配置改对象on/as前缀让配置天然支持事件与行为挂载Yii::$container-set()让默认配置全局生效YII_ENV系列常量让配置随环境自动切换。把这一套机制吃透无论是写入口脚本、组织应用组件还是定制第三方小部件都能做到结构清晰、改动局部化、环境切换零成本。文中涉及的源码均可在本仓库 framework/BaseYii.php、framework/di/Container.php、framework/base/Component.php 中查阅相关概念可继续阅读属性、事件、行为与依赖注入容器章节。【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。