Yii视图片段缓存需配对使用beginCache()和endCache(),漏掉后者会导致页面截断;缓存键默认基于视图路径生成,支持dependency自动失效,duration设为0时依赖缓存组件TTL而非永不过期。

视图里用 beginCache() 就能开片段缓存,但得配对调用 endCache()
Yii 的视图缓存核心就是 beginCache() 和 endCache() 这一对函数,不是配置开关、也不依赖控制器注解。漏掉 endCache() 会导致后续所有输出被吞掉——页面直接截断,连 HTML 结束标签都不见,浏览器里看源码会发现 </body> 后面啥也没有。
常见错误现象:500 错误没报,但页面下半截空白;或者控制台看到 ob_start(): failed to create buffer 类似提示(尤其在调试模式下)。
-
beginCache()必须在视图文件(.php)里调用,不能放在布局或小部件里跨作用域使用 - 缓存键默认由当前视图路径 + 参数生成,如果传了
['dependency' => new \yii\caching\FileDependency(['fileName' => __FILE__])],改视图文件内容会自动失效缓存 - 别在
beginCache()区块里写echo或直接输出 HTML,要用return方式让内容进缓冲区(Yii 内部靠输出缓冲实现)
duration 参数不设默认是 0,意味着“永不过期”,但实际受缓存组件 TTL 限制
很多人以为 duration 是“必须填的”,其实不填或设为 0 时,Yii 会跳过时间判断,只依赖缓存依赖项(dependency)是否变化。但注意:底层用的 cache 组件(比如 redis 或 file)本身有最大存活时间(TTL),例如 Redis 默认 defaultDuration 是 3600 秒,这时候即使你代码里写 ['duration' => 0],缓存也最多活一小时。
- 显式设
duration => 600表示 10 分钟后强制过期,不管依赖有没有变 - 设
duration => 0+dependency是更安全的做法,适合模板内容随数据库/文件变化的场景 - 如果用
apcu缓存,注意它不支持 TTL,duration实际无效,全靠dependency驱动刷新
页面级缓存得靠控制器行为(PageCache),不是视图函数
想整个 action 输出缓存?别在视图里折腾 beginCache(),那是片段级的。页面缓存必须在控制器里声明行为:PageCache。它拦截的是响应体生成前的整个流程,包括 layout 渲染,所以比视图缓存更彻底,但也更难调试。
-
PageCache不执行控制器的action方法体,也不走beforeAction,缓存命中就直接返回,这点和视图缓存完全不同 - 缓存键默认含 GET 参数,但如果你加了
'variations' => ['Yii::$app->language'],多语言站点就不会混用缓存 - POST 请求默认不缓存,但如果手动配了
'only' => ['index']又没限制 method,可能意外缓存 POST 响应(危险!)
缓存键里带用户信息?小心 Yii::$app->user->id 在未登录时是 null
片段缓存常要个性化,比如“我的订单列表”。直接写 ['key' => 'orders-' . Yii::$app->user->id] 看似合理,但游客访问时 Yii::$app->user->id 是 null,结果所有游客共用一个缓存键,互相看到对方空列表。这不是 bug,是预期行为——但容易被忽略。
- 正确做法是先判断:
$uid = Yii::$app->user->isGuest ? 'guest' : Yii::$app->user->id; - 如果用
dependency关联用户数据表,记得查主键而非昵称等可变字段,否则更新昵称也会误刷缓存 - Redis 中用
KEYS orders-*能扫出缓存键,但生产环境禁用该命令,建议用SCAN替代,不然会卡住实例
缓存不是开个开关就完事,关键是理清“谁在读、谁在写、谁会变”。键设计、依赖粒度、组件选型这三块,错一个,缓存就从加速器变成定时雷。


















