从 Yii 1.1 升级到 Yii 2.0:核心架构差异与迁移实践全指南(Yii 2 Framework)
从 Yii 1.1 升级到 Yii 2.0:核心架构差异与迁移实践全指南(Yii 2 Framework)
Yii 2.0 是相对 1.1 完全重写的一代框架,两者在命名空间、对象模型、事件机制、Active Record 与视图渲染等层面存在系统性差异。本文以官方《Upgrading from Version 1.1》(俄文版 docs/guide-ru/intro-upgrade-from-v1.md)为骨架,结合 framework 源码实现,逐项梳理 1.1 → 2.0 的主要差异、迁移时的代码改写要点与底层原理,帮助你从 1.1 代码平滑过渡到 2.0,并识别出那些在 2.0 中已经内建、无需再自行开发的功能。
适用前提:本仓库当前为 Yii 2.0 系列(
BaseYii::getVersion()返回2.0.56-dev,见 framework/BaseYii.php)。文中所有类名、路径与行为均以本仓库源码为准。如果你从未使用过 Yii 1.1,可跳过本文,直接阅读 开始使用。
一、迁移总览:为什么 1.1 → 2.0 不是一次普通的升级
Yii 在 2.0 中进行了彻底重写(complete rewrite),因此从 1.1 升级到 2.0 远不止是版本号的变化,而是一次系统性的代码迁移。官方文档给出了两个重要提醒:
- 本文只覆盖两个版本间的主要差异,2.0 实际引入的新特性远多于本文列举的内容;
- 强烈建议完整通读整个权威指南,因为很多过去需要你自行开发的功能,如今已经是框架核心的一部分。
迁移的大方向可以概括为:类名去 "C" 前缀并引入命名空间、对象配置统一化、事件与行为机制重做、视图/模型/控制器职责更清晰、数据访问层(Query Builder 与 Active Record)重构。下面各节逐项展开。
二、安装方式与 PHP 版本要求
2.1 安装:全面拥抱 Composer
Yii 2.0 全面采用 Composer;如果你要创建新扩展或把已有的 1.1 扩展改造为 2.0 兼容扩展,见 创建扩展。
2.2 PHP 版本要求与语言级差异
Yii 1.1 要求 PHP 5.2,而 Yii 2.0 要求 PHP 5.4 或更高(本仓库的 composer.json 中 require 即体现了对现代 PHP 的依赖)。这一提升带来了大量语言层面的变化,迁移代码时需要注意:
- 命名空间(Namespaces):2.0 的代码全部基于命名空间组织;
- 匿名函数(Anonymous functions):事件处理器、回调等大量使用闭包;
- 短数组语法:用
[...元素...]替代array(...元素...); - 短 echo 标签
<?=:自 PHP 5.4 起可安全地在视图文件中直接使用; - SPL 类与接口:
ArrayAccess、IteratorAggregate等被框架大量实现(例如yii\base\Model就实现了IteratorAggregate、ArrayAccess、Arrayable,见 framework/base/Model.php); - 后期静态绑定(Late Static Bindings, LSB):支撑了
Widget::widget()、AssetBundle::register()这类静态工厂调用; - 日期时间类(DateTime):框架与业务代码的时间处理基于 PHP 内置类;
- Trait(性状):框架内部大量使用 trait 复用代码(如
Model中的ArrayableTrait、StaticInstanceTrait); - intl 扩展:Yii 2.0 依赖 PHP
intl扩展来支撑国际化功能(详见后文 I18N 一节)。
三、命名空间与自动加载
最直观的变化:几乎每一个框架核心类都进入了命名空间,例如 yii\web\Request;类名上的 "C" 前缀被彻底移除(CComponent → Component,CController → Controller,CModel → Model 等)。
类名与目录结构一一对应:yii\web\Request 对应的类文件就是框架目录下的 web/Request.php(本仓库实际路径 framework/web/Request.php)。
无需显式 include:得益于 Yii 的类自动加载器,你可以直接使用任意核心类而无需手动 require。自动加载机制的核心实现在 framework/BaseYii.php 的 autoload():先查 classMap,对于带命名空间的类则通过 getAlias('@' . str_replace('\\', '/', $className) . '.php') 解析到对应文件并 include。例如,只要 @yii 别名指向框架目录(框架默认注册 '@yii' => __DIR__,见 framework/BaseYii.php),yii\web\Request 就能被自动解析为 @yii/web/Request.php 并加载。
四、Component 与 Object:一对二的拆分
1.1 中的 CComponent 在 2.0 中被拆分为两个类:
| 1.1 | 2.0 | 职责 |
|---|---|---|
CComponent |
yii\base\BaseObject |
轻量基类,通过 getter/setter 提供**属性(property)**能力,不携带事件/行为 |
| (继承关系) | yii\base\Component |
继承 BaseObject,额外支持事件(events)与行为(behaviors) |
- 什么时候用
BaseObject:如果你的类不需要事件和行为特性(典型如纯数据结构类),建议直接继承BaseObject。 Component的完整能力:除属性外还支持事件与行为。从源码看,Component内部维护_events(事件名 → 处理器列表)、_eventWildcards(通配符事件)和_behaviors(已附加的行为),见 framework/base/Component.php。事件名是大小写敏感的,而BaseObject的属性名是大小写不敏感的(见 framework/base/BaseObject.php 的文档注释)。
五、对象配置:统一的对象初始化约定
BaseObject 引入了一套统一的对象配置方式。任何 BaseObject 的子类若需自定义构造函数,都应遵循如下约定(最后一个参数必须是配置数组,且构造函数末尾调用 parent::__construct($config)):
class MyClass extends \yii\base\BaseObject
{
public function __construct($param1, $param2, $config = [])
{
// ... 配置应用之前的初始化
parent::__construct($config);
}
public function init()
{
parent::init();
// ... 配置应用之后的初始化
}
}
生命周期:从 framework/base/BaseObject.php 的注释可以看出,BaseObject 的构造过程分三步依次进行:① 构造函数被调用;② 根据给定的配置数组初始化对象属性;③ 调用 init() 方法。其构造器实现为 Yii::configure($this, $config) 之后调用 $this->init()(见 framework/base/BaseObject.php)。因此,需要依赖"配置已应用"这一前提的初始化逻辑,应放在 init() 中而不是构造函数里。
遵守此约定后,就可以用配置数组统一地创建和配置对象:
$object = Yii::createObject([
'class' => 'MyClass',
'property1' => 'abc',
'property2' => 'cde',
], [$param1, $param2]);
Yii::createObject() 是 new 操作符的增强版:支持按类名、配置数组或可调用对象创建实例,并且能借助依赖注入容器自动装配依赖(见 framework/BaseYii.php)。更多配置细节见 配置。
六、事件:从 "on 方法" 到任意事件名 + trigger
在 Yii 1 中,事件通过声明 on 方法实现(例如 onBeforeSave),事件名被硬编码进方法名。Yii 2 中可以使用任意事件名,并通过 Component 的方法显式触发与绑定:
// 触发事件
$event = new \yii\base\Event;
$component->trigger($eventName, $event);
// 绑定事件处理器
$component->on($eventName, $handler);
// 移除处理器
// $component->off($eventName, $handler);
从源码看,事件处理器支持四种类型:匿名函数、对象方法(<a href="https://link.gitcode.com/i/ec46afcd975d6376cba9aa4416c92ba6" target="_blank">$object, 'handleAdd'])、静态类方法(['Page', 'handleAdd'])、全局函数('handleAdd');处理器签名统一为 function ($event),可通过 $event->data 访问附加数据(见 [framework/base/Component.php)。此外 2.0 还支持在配置数组中用 'on add' => handler 的语法直接附加事件、用 'as tree' => <a href="https://link.gitcode.com/i/8e362cc43cbc8e6b60607b75863c0b8b" target="_blank">...] 的语法附加行为(同上源码注释)。事件的更多增强特性见 [事件。
七、路径别名:@ 前缀与自动加载的关联
Yii 2.0 将别名(alias)的使用范围扩大到文件/目录路径与 URL,并且强制要求别名以 @ 开头,以与普通路径和 URL 区分。例如别名 @yii 指向 Yii 的安装目录。
- 别名的底层实现:
BaseYii内置$aliases = <a href="https://link.gitcode.com/i/e3da449a4eb1797fa68fccb93ea07d4e" target="_blank">'@yii' => __DIR__];setAlias()注册别名(自动补@前缀、去除末尾/、支持把别名指向另一个别名),getAlias()按"最长匹配优先、/为边界符"的规则把别名翻译为真实路径,未注册的根别名会抛出InvalidArgumentException(见 [framework/BaseYii.php)。 - 别名无处不在:例如
yii\caching\FileCache::cachePath既接受路径别名也接受普通目录路径。 - 别名与类命名空间紧密相关:官方建议为每个根命名空间定义一个路径别名,这样无需额外配置即可使用 Yii 类自动加载器。因为
@yii指向框架目录,yii\web\Request可被自动加载;如果你使用 Zend Framework 等第三方库,可定义@Zend指向其安装目录,之后 Yii 就能自动加载其中的任何类。
更多内容见 路径别名。
八、视图(View):$this 语义的根本变化
1.1 → 2.0 最大的视图变化:视图文件中的特殊变量 $this 不再指向当前控制器或小部件,而是指向一个视图对象(类型为 yii\web\View,代表 MVC 模式中的 View 部分)。视图对象的 context 属性保存其上下文,因此在视图中访问控制器或小部件应使用 $this->context(见 framework/base/View.php 中 public $context 的定义)。
渲染部分视图的方式变化:原来用 $this->renderPartial(),2.0 中用 $this->render();且 render() 返回渲染结果而非直接输出,因此必须显式 echo:
echo $this->render('_item', ['item' => $item]);
模板引擎:除了以 PHP 作为主要模板语言,2.0 官方支持 Smarty 与 Twig 两个流行模板引擎,不再支持 Prado 模板引擎。使用 Smarty/Twig 需要配置应用组件 view 的 View::$renderers 属性——该属性是一个按文件扩展名索引的渲染器数组,例如 'tpl' => <a href="https://link.gitcode.com/i/158df2c9af4a28452a478cd4f26f598a" target="_blank">'class' => 'yii\smarty\ViewRenderer']、'twig' => ['class' => 'yii\twig\ViewRenderer'];若视图文件没有匹配的渲染器,则按普通 PHP 渲染(见 [framework/base/View.php)。详见 模板引擎。
九、模型(Model):scenarios() 取代 on 方法时代
Yii 2.0 以 yii\base\Model 作为模型基类,对应 1.1 的 CModel。CFormModel 类已被完全移除——需要创建表单模型时,直接继承 yii\base\Model 即可。
新增 scenarios() 方法用于声明支持的场景,并标明某属性在哪个场景下需要验证、是否安全等:
public function scenarios()
{
return [
'backend' => ['email', 'role'],
'frontend' => ['email', '!role'],
];
}
上例声明了两个场景:backend 场景下 email 与 role 都是安全属性,可以被批量赋值(massive assignment);frontend 场景下 email 可批量赋值,而 role 不可(前缀 ! 表示不安全)。两个属性都需要用验证规则进行校验。
rules() 方法仍然用于声明验证规则。由于 scenarios() 的出现,不再有 unsafe 验证器。从源码看,scenarios() 的默认实现会自动从 rules() 中推导出场景与活动属性:默认场景 SCENARIO_DEFAULT(常量值为 'default',见 framework/base/Model.php)包含所有规则涉及的属性,各命名场景则由规则中的 on/except 选项决定(见 framework/base/Model.php)。
实践建议:在大多数情况下,如果 rules() 已经完整描述了所有存在的场景,且不需要声明不安全属性,就无需覆写 scenarios()。
rules() 中规则的完整结构(依据 framework/base/Model.php 的文档注释):
[
[['username', 'password'], 'required'], // 内置必填验证器
['username', 'string', 'min' => 3, 'max' => 12], // 内置 string 验证器 + 参数
['password', 'compare', 'compareAttribute' => 'password2', 'on' => 'register'], // 仅 register 场景生效
['password', 'authenticate', 'on' => 'login'], // 内联验证器(模型方法)
['dateRange', 'DateRangeValidator'], // 自定义验证器类
];
关于 Model 的更多信息见 模型。
十、控制器(Controller):返回结果而非直接输出
Yii 2.0 以 yii\web\Controller 作为控制器基类(对应 1.1 的 CController),yii\base\Action 是所有动作类的基类。
对代码最直接的影响:控制器动作应返回要渲染的内容,而不是直接 echo 输出:
public function actionView($id)
{
$model = \app\models\Post::findOne($id);
if ($model) {
return $this->render('view', ['model' => $model]);
} else {
throw new \yii\web\NotFoundHttpException;
}
}
路由命名约定:控制器与动作的驼峰命名会被转换为小写并用连字符分隔,例如控制器类 CamelCaseController 的控制器 ID 是 camel-case。详见 控制器 ID 与动作 ID。更多控制器细节见 控制器。
十一、小部件(Widget):静态方法 begin / end / widget
Yii 2.0 以 yii\base\Widget 作为小部件基类(对应 1.1 的 CWidget)。为了获得更好的 IDE 支持,2.0 引入了新的静态方法语法:
use yii\widgets\Menu;
use yii\widgets\ActiveForm;
// 注意:必须 echo 结果才会显示
echo Menu::widget(['items' => $items]);
// 传入数组以初始化对象属性
$form = ActiveForm::begin([
'options' => ['class' => 'form-horizontal'],
'fieldConfig' => ['inputOptions' => ['class' => 'input-xlarge']],
]);
... 表单字段 ...
ActiveForm::end();
底层原理:Widget::widget() 的实现会开启输出缓冲(ob_start())、创建小部件实例并返回其 run() 的输出;begin()/end() 通过内部栈(self::$stack)管理嵌套小部件的生命周期(见 framework/base/Widget.php)。这一设计让 ActiveForm::begin() ... ActiveForm::end() 这样的成对调用成为可能。更多信息见 小部件。
十二、主题(Theming):基于路径映射的全新机制
Yii 2.0 的主题机制完全重做,基于源视图文件路径 → 主题化视图文件路径的映射。例如路径映射 ['/web/views' => '/web/themes/basic'] 意味着视图文件 /web/views/site/index.php 的主题化版本位于 /web/themes/basic/site/index.php。
关键变化:
- 主题现在可以应用于任何视图文件,即使该视图是在控制器或小部件上下文之外渲染的;
- 不再有
CThemeManager组件;取而代之,theme成为应用组件view的一个可配置属性。
从源码看,View::$theme 属性接受主题对象、配置数组或字符串(见 framework/base/View.php),且在 View::init() 中会把配置数组规范化(未显式指定 class 时默认为 yii\base\Theme,见 framework/base/View.php)。详见 主题化。
十三、控制台应用(Console):控制器化的命令体系
控制台应用现在像 Web 应用一样按控制器组织。控制台控制器应继承 yii\console\Controller(对应 1.1 的 CConsoleCommand)。
运行方式:使用 yii <路由>,其中 <路由> 是控制器路由(例如 sitemap/index)。额外的匿名参数会作为对应动作方法的参数传入,而命名参数则按照 yii\console\Controller::options() 中的声明解析。
帮助信息自动生成:Yii 2.0 支持从注释块自动生成命令帮助信息。有关控制台命令的完整说明见 控制台命令。
十四、I18N:intl 扩展与 i18n 应用组件
Yii 2.0 移除了内置的日期格式器和数字格式器,转而使用 PECL intl PHP 扩展。
消息翻译现在通过 i18n 应用组件完成。该组件管理一组消息源(message sources),允许你根据消息类别(category)为源消息使用不同的存储来源。详见 国际化。
十五、动作过滤器(Action Filters):行为化实现
动作过滤器现在通过行为(behaviors)实现。定义新过滤器时继承 yii\base\ActionFilter;使用过滤器时,把它作为行为附加到控制器上。例如使用 yii\filters\AccessControl 过滤器:
public function behaviors()
{
return [
'access' => [
'class' => 'yii\filters\AccessControl',
'rules' => [
['allow' => true, 'actions' => ['admin'], 'roles' => ['@']],
],
],
];
}
上例中 roles => <a href="https://link.gitcode.com/i/c98aac66e5d4cf0b55fab9420fe3de00" target="_blank">'@'] 表示仅允许已认证用户访问 admin 动作。过滤器基类位于 [framework/base/ActionFilter.php,内置过滤器(如 AccessControl、VerbFilter、Cors、RateLimiter 等)位于 framework/filters。更多信息见 过滤器。
十六、资源(Assets):资源包(Asset Bundle)取代脚本包
Yii 2.0 引入**资源包(asset bundle)**新概念,取代了 1.1 的脚本包(script package)。
- 资源包是某一目录下资源文件(JavaScript、CSS、图片等)的集合,每个资源包用一个继承
yii\web\AssetBundle的类表示; - 通过
AssetBundle::register()注册后,包内资源即可通过 Web 访问; - 与 1.1 的关键区别:注册资源包的页面会自动包含包中声明的 JavaScript 与 CSS 文件引用。
从源码看,AssetBundle 的核心属性包括 sourcePath(源目录)、js(JS 文件列表)、css(CSS 文件列表)、jsOptions/cssOptions(注册选项)、publishOptions(发布选项)等(见 framework/web/AssetBundle.php);register() 实际调用视图的 registerAssetBundle() 完成注册(见 framework/web/AssetBundle.php)。框架自带的基础资源包示例见 framework/assets(如 yii\assets\YiiAsset、yii\assets\ActiveFormAsset 等)。更多信息见 管理资源。
十七、辅助类(Helpers):常用静态工具类
Yii 2.0 内置了大量常用的静态辅助类,主要包括:
yii\helpers\Htmlyii\helpers\ArrayHelperyii\helpers\StringHelperyii\helpers\FileHelperyii\helpers\Json
这些类的实现位于 framework/helpers。更多信息见 辅助类总览。
十八、表单(Forms):ActiveField 字段概念
Yii 2.0 引入**字段(field)**概念,用于配合 yii\widgets\ActiveForm 构建表单。一个字段是包含标签、输入控件、错误消息和/或提示文本的容器,用 yii\widgets\ActiveField 对象表示。使用字段可以更简洁地构建表单:
<?php $form = yii\widgets\ActiveForm::begin(); ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<div class="form-group">
<?= Html::submitButton('Login') ?>
</div>
<?php yii\widgets\ActiveForm::end(); ?>
ActiveField 支持链式调用输入方法(如 ->passwordInput()、->textInput()、->dropDownList() 等),并可配合 hint()、error()、label() 等细化渲染。相关实现位于 framework/widgets/ActiveField.php 与 framework/widgets/ActiveForm.php。更多信息见 创建表单。
十九、查询构建器(Query Builder):统一为 Query 对象
在 1.1 中,查询构建分散在多个类中:CDbCommand、CDbCriteria、CDbCommandBuilder。Yii 2.0 用 yii\db\Query 对象表示一次数据库查询,并可在后台由 yii\db\QueryBuilder 转换为 SQL 语句:
$query = new \yii\db\Query();
$query->select('id, name')
->from('user')
->limit(10);
$command = $query->createCommand();
$sql = $command->sql;
$rows = $command->queryAll();
Query 提供 select()、from()、where()、andWhere()、orderBy()、limit()/offset()、join() 等链式方法;createCommand() 通过 QueryBuilder 生成 SQL 并返回 yii\db\Command 实例。核心实现见 framework/db/Query.php 与 framework/db/QueryBuilder.php。更优做法:这些查询构建方法也可以配合 Active Record 使用。更多信息见 查询构建器。
二十、Active Record:查询、关联与性能的全面重构
Yii 2.0 对 Active Record 做了大量修改,最明显的是查询构建与关联处理两个方面。
20.1 查询:ActiveQuery 取代 CDbCriteria
1.1 的 CDbCriteria 被 yii\db\ActiveQuery 取代。该类继承自 yii\db\Query,因此继承了全部查询构建方法。调用 ActiveRecord::find() 开始构建查询:
// 获取所有 *激活* 状态的客户并按 ID 排序
$customers = Customer::find()
->where(['status' => $active])
->orderBy('id')
->all();
20.2 关联:getter 即关联声明
声明关联只需声明一个返回 ActiveQuery 对象的 getter 方法,getter 定义的属性名就是关联名(而在 1.1 中,你需要在统一的 relations() 方法中集中声明所有关联):
class Customer extends \yii\db\ActiveRecord
{
public function getOrders()
{
return $this->hasMany('Order', ['customer_id' => 'id']);
}
}
现在可以直接用 $customer->orders 访问客户的订单;也可以在需要时"即时"附加查询条件:
$orders = $customer->getOrders()->andWhere('status=1')->all();
20.3 预加载(Eager Loading)策略变化
Yii 2.0 的预加载方式与 1.1 不同:1.1 用一条 JOIN 查询同时取回主记录与关联记录;2.0 执行两条不带 JOIN 的 SQL——第一条取主表记录,第二条按主表主键过滤取关联表记录。
20.4 asArray():大数据量场景的性能优化
当需要取出大量记录时,与其返回 ActiveRecord 对象,不如在查询中链式调用 ActiveQuery::asArray()。这会让查询结果以数组形式返回,在处理大量记录时可显著降低 CPU 耗时与内存占用:
$customers = Customer::find()->asArray()->all();
20.5 默认值:从 public 属性移到 init()
不能再用 public 属性定义属性默认值了。如有需要,应在记录类的 init() 方法中设置:
public function init()
{
parent::init();
$this->status = self::STATUS_NEW;
}
20.6 构造函数的自由度
1.1 中覆写 ActiveRecord 构造函数存在一些问题,2.0 中已不再有这些问题。注意:若你给构造函数添加了参数,可能需要同时覆写 ActiveRecord::instantiate()。
Active Record 还有大量其他改进,详见 Active Record。
二十一、Active Record 行为(Behaviors):直接继承 Behavior
2.0 已移除基类 CActiveRecordBehavior。要创建 Active Record 行为,应直接继承 yii\base\Behavior。如果行为需要响应所属对象的某些事件,必须覆写 events() 方法:
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// ...
}
}
注意 EVENT_BEFORE_VALIDATE 等事件常量定义于 yii\base\Model(见 framework/base/Model.php),ActiveRecord 继承自 Model 因而可用。更多行为知识见 行为。
二十二、User 与 IdentityInterface:认证体系的重构
1.1 的 CWebUser 被 yii\web\User 取代,CUserIdentity 类不复存在。取而代之,你需要实现 yii\web\IdentityInterface 接口,使用起来更加直接明了。高级项目模板(advanced project template)中提供了参考实现。
核心接口定义见 framework/web/IdentityInterface.php,User 组件实现见 framework/web/User.php。更多信息见 认证、授权 与高级项目模板相关文档。
二十三、URL 管理:可选参数与路由命名
Yii 2.0 的 URL 管理与 1.1 类似,主要增强是支持可选参数。例如下面的规则能同时匹配 post/popular 与 post/1/popular——在 1.1 中要达到同样效果需要写两条规则:
[
'pattern' => 'post/<page:\d+>/<tag>',
'route' => 'post/index',
'defaults' => ['page' => 1],
]
这里 <page:\d+> 是带正则约束的参数占位符,defaults 为可选参数提供默认值。详见 URL 解析与生成。
路由命名约定的重要变化:控制器和动作的驼峰命名现在会转换为小写、单词间以连字符分隔(如 CamelCaseController 的控制器 ID 为 camel-case)。详见 控制器 ID 与 动作 ID 相关章节。
二十四、同时使用 Yii 1.1 与 2.x
如果你有希望与 Yii 2.0 共存的遗留 1.1 代码,请参考 同时使用 Yii 1.1 和 2.0 一节(该指南的英文版对应 tutorial-yii-integration.md)。
迁移速查:1.1 → 2.0 关键对照表
| 主题 | Yii 1.1 | Yii 2.0 |
|---|---|---|
| 类名风格 | C 前缀(CComponent、CController) |
命名空间 + 无前缀(yii\base\Component、yii\web\Controller) |
| 基类拆分 | CComponent |
yii\base\BaseObject(属性)/ yii\base\Component(属性+事件+行为) |
| 对象配置 | 无统一约定 | 构造器末尾 $config 参数 + init(),配合 Yii::createObject() |
| 事件 | on 方法(onBeforeSave) |
任意事件名 + trigger()/on()/off() |
视图 $this |
指向控制器/小部件 | 指向视图对象($this->context 访问上下文) |
| 部分视图渲染 | renderPartial() |
$this->render() + 显式 echo |
| 表单模型 | CFormModel |
直接继承 yii\base\Model |
| 场景/安全性 | safe/unsafe 验证器 |
scenarios() + ! 前缀标记不安全属性 |
| 控制器输出 | 直接 echo | return 渲染结果 |
| 小部件 | 实例化调用 | 静态 Widget::widget() / begin() / end() |
| 主题 | CThemeManager |
view 组件 theme 属性 + 路径映射 |
| 控制台 | CConsoleCommand |
yii\console\Controller + yii <路由> |
| 动作过滤器 | 独立机制 | 继承 yii\base\ActionFilter + 作为行为附加 |
| 前端资源 | 脚本包 | yii\web\AssetBundle 资源包 |
| 查询构建 | CDbCommand/CDbCriteria/CDbCommandBuilder |
yii\db\Query + yii\db\QueryBuilder |
| AR 查询 | CDbCriteria |
yii\db\ActiveQuery(继承 Query) |
| AR 关联 | relations() 集中声明 |
getter 方法返回 ActiveQuery |
| AR 预加载 | JOIN 单查询 | 两条独立 SQL(无 JOIN) |
| AR 默认值 | public 属性 | init() 中设置 |
| AR 行为 | CActiveRecordBehavior |
直接继承 yii\base\Behavior + events() |
| 用户认证 | CWebUser / CUserIdentity |
yii\web\User / 实现 yii\web\IdentityInterface |
| URL 规则 | 无可选参数 | 支持可选参数(defaults) |
| 路由命名 | 原样保留 | 驼峰转连字符小写 |