Yii2 中 Component 是支持属性、事件、行为的基类,比 Object 多 events 和 behaviors 开销;仅需属性和配置时用 Object 更轻量,需事件或行为时才用 Component。

不能吃,但能“装”——yii\base\Component 是个带插槽的容器,不是食物,是 Yii2 里支持属性、事件、行为这三样扩展能力的基类。
Component 和 Object 到底差在哪?
区别就一条:要不要为事件(on() / trigger())和行为(attachBehavior())预留开销。如果只是存几个字段、跑点逻辑,用 yii\base\Object 更轻;一旦你要监听“用户登录了”“订单创建了”,或者想临时给类加个日志功能,就得上 Component。
-
Object:只管属性(__get/__set)、配置($config)、init(),没事件、没行为,内存和 CPU 更省 -
Component:在Object基础上加了events数组和behaviors管理,每次trigger()都要遍历 handlers,每个getBehavior()都有查找成本 - 别为了“看起来高级”继承
Component——比如一个只做数据转换的PriceFormatter,用Object就够了
为什么配置里写的组件能“动起来”?
因为 Yii 应用启动时,会把 components 配置数组里的每一项,按需实例化成对象,并缓存在 Yii::$app->getComponents() 里。你写 'mailer' => ['class' => 'yii\swiftmailer\Mailer', ...],框架实际执行的是:new Mailer($config),且只在第一次调用 Yii::$app->mailer 时才真正创建。
- 配置项中的
on xxx键(如'on beforeRequest')会被自动转成on('beforeRequest', ...)调用 - 配置里的
as xxx(如'as access' => AccessControl::class)会触发attachBehavior() - 动态改组件?别直接改
Yii::$app->mailer->transport->host,得先Yii::$app->set('mailer', [...])或重建实例,否则下次从容器取还是旧的
自己写组件时最容易翻车的三件事
不是语法错,而是生命周期和设计意图没对齐。
- 重写了
__construct()却忘了把$config传给父类:parent::__construct($config)缺了这句,init()不会执行,属性也不会被自动赋值 - 在
init()里访问了还没初始化的依赖,比如$this->db—— 此时Yii::$app->db可能都还没创建,应改用延迟获取:Yii::$app->get('db') - 把事件 handler 写成闭包并存在属性里(如
$this->onSave = function() {...}),结果序列化时报错或内存泄漏;正确做法是统一用on('save', [...])注册,让框架管理生命周期
Component 的本质不是“必须用”,而是“按需加载扩展能力”。很多开发者一上来就继承它,结果发现接口响应慢了 5ms——那 5ms 就花在了没用上的事件循环和行为查找上。


















