必须放进 bootstrap 数组的组件是 log、errorHandler、urlManager;它们不依赖请求上下文但需在首个请求前就绪,否则启动错误或路由解析会失败;db、cache 等支持懒加载,不应提前初始化。

哪些组件必须放进 bootstrap 数组
只有那些「需要在 request 处理前就 ready」的组件才该进 bootstrap。比如 log、errorHandler、urlManager——它们不依赖请求上下文,但必须在第一个请求进来前就准备好,否则启动阶段的错误或路由解析会失败。
常见误用:把 db 或 cache 塞进 bootstrap。它们本身支持懒加载,提前初始化没收益,反而拖慢冷启动;除非你明确要在 init() 里执行建表、预热缓存等操作。
-
log必须放,否则Yii::info()在应用构造后、run()前的日志会丢 -
errorHandler必须放,否则启动时报错无法被捕获,直接暴露 PHP 错误 -
security或authManager可选放,仅当你需要在控制器执行前完成 RBAC 规则加载时才需要
bootstrap 里写类名 vs 写组件 ID 的区别
写 'log' 是取已注册的组件(必须在 components 中定义),Yii 调用 getComponent('log') 后执行 init();写 'app\components\MyBootstrapService' 则是 new 出新实例,不挂载到 Yii::$app 属性上,只执行一次 init()。
关键差异在于作用域和复用性:
- 用组件 ID:可被其他地方通过
Yii::$app->log访问,适合日志、路由这类全局服务 - 用类名:纯一次性初始化,适合做环境检查、配置补全等无状态操作,比如检查
@runtime目录权限 - 混用风险:若类名未实现
BootstrapInterface,且没定义init()方法,会静默跳过,不报错也不生效
为什么 init() 里访问 Yii::$app->response 会出问题
因为 response 组件虽然在 components 里定义了,但它在 Application::init() 阶段才被 setup,而 bootstrap 组件的 init() 是在 Application 构造完、init() 执行前触发的——此时 Yii::$app->response 还只是个空壳,getHeaders() 或 send() 会触发未初始化异常。
安全做法:
- 读
Yii::$app->request没问题,它比 bootstrap 更早 setup - 要操作 response,改用事件监听:
Yii::$app->on(Application::EVENT_BEFORE_REQUEST, function () { ... }); - 或者把逻辑移到
BootstrapInterface::bootstrap($app),这时$app已完全初始化
顺序依赖导致的“组件未定义”陷阱
bootstrap 是按数组顺序逐个 getComponent() 的。如果 A 组件的 init() 里写了 Yii::$app->B,而 B 在数组里排在 A 后面,就会拿到 null 或未 fully-init 的对象。
典型场景:
- 自定义
RequestFilter组件依赖user组件做登录态校验,但'user'写在了数组末尾 -
queue组件在init()里调用Yii::$app->db->createCommand(),但db没进 bootstrap,且不在 components 定义中 - 解决办法只有两个:调整数组顺序,或改用
BootstrapInterface,在统一入口里控制依赖链
真正容易被忽略的是:这种错误不会立即抛异常,而是运行时行为异常(比如鉴权跳过、队列任务不触发),排查成本远高于配置时多看一眼顺序。


















