Yii 2 片段缓存(Fragment Caching)完全指南:从基本用法到嵌套缓存与动态内容
Yii 2 片段缓存Fragment Caching完全指南从基本用法到嵌套缓存与动态内容【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2片段缓存Fragment Caching是 Yii 2 框架中用于缓存 Web 页面局部片段的高阶缓存能力它建立在数据缓存之上可在视图View层通过一对方法调用把耗时生成的页面区块如年度销售汇总表、文章正文缓存起来从而消除每次请求重复生成这些内容的时间开销。阅读本文后你将掌握片段缓存的标准用法、duration/dependency/variations/enabled四大选项的配置技巧、嵌套缓存与动态内容的正确姿势并通过源码级剖析理解其底层实现原理与失效机制。什么是片段缓存片段缓存指的是缓存 Web 页面中的一个片段。例如如果一个页面用表格展示年度销售汇总你可以把这张表格存入缓存省去每次请求重新生成表格的时间。片段缓存构建在数据缓存之上本质上是「数据缓存的视图层封装」它以数据缓存为存储后端由视图组件提供专用的调用入口。与数据缓存一样片段缓存同样需要一个唯一的$id来标识一段被缓存的内容。基本用法beginCache 与 endCache要使用片段缓存只需在视图中使用如下构造if ($this-beginCache($id)) { // ...在这里生成内容... $this-endCache(); }也就是说把内容生成逻辑包在beginCache()与endCache()这对调用之间。执行语义如下如果内容在缓存中命中beginCache()会直接渲染出缓存内容并返回false从而跳过内容生成逻辑否则内容生成逻辑会被执行当调用endCache()时生成的内容会被捕获并存入缓存。这两个方法都定义在yii\base\View中。从源码看beginCache($id, $properties [])会把$id和当前视图对象注入属性数组然后以yii\widgets\FragmentCache组件开启一个小部件若缓存内容可用则立即调用endCache()并返回false否则返回true表示「请生成内容」。删除片段缓存当需要主动清除某个片段的缓存时例如后台编辑文章后可以直接操作底层缓存组件Yii::$app-cache-delete([yii\widgets\FragmentCache, $id]);这里的删除键[yii\widgets\FragmentCache, $id]并非随意编写而是与源码中FragmentCache::calculateKey()的键构造逻辑严格对应——该方法生成array_merge([__CLASS__, $this-getId()], (array)$this-variations)作为缓存键__CLASS__即yii\widgets\FragmentCache。因此若不使用variations选项按上述写法即可精确删除对应片段若使用了variations则需在删除键中补上相同的变体值。缓存选项除了$id你还可以把选项数组作为第二个参数传给yii\base\View::beginCache()。在后台这个选项数组会被用来配置一个真正实现片段缓存功能的yii\widgets\FragmentCache小部件。下表汇总了全部核心选项选项类型默认值作用durationint60缓存内容有效秒数设为 0 表示永不过期dependencyDependency对象或配置数组无声明缓存内容所依赖的依赖对象variations标量值数组无使缓存内容随不同因素语言、GET 参数等产生多个版本enabledbooltrue是否启用片段缓存cache缓存组件cache使用的缓存组件 ID源码属性见下文下面逐一说明各选项的用法与实现细节。duration缓存有效期duration是片段缓存最常用的选项它指定内容在缓存中最多可保持有效多少秒。下面的代码把片段内容最多缓存一小时if ($this-beginCache($id, [duration 3600])) { // ...在这里生成内容... $this-endCache(); }如果该选项未设置将使用默认值 60即缓存内容在 60 秒后过期。这一点在源码FragmentCache::$duration中有明确声明同时源码注释说明设为0表示缓存数据永不失效该语义与数据缓存Cache::set()的duration约定一致。dependency缓存依赖与数据缓存一样被缓存的片段内容也可以声明依赖。例如一篇文章显示的内容依赖于文章是否被修改过。指定依赖时设置dependency选项它可以是yii\caching\Dependency对象也可以是用于创建依赖对象的配置数组。下面的代码指定片段内容依赖updated_at列值的变化$dependency [ class yii\caching\DbDependency, sql SELECT MAX(updated_at) FROM post, ]; if ($this-beginCache($id, [dependency $dependency])) { // ...在这里生成内容... $this-endCache(); }当post表中任一文章的updated_at发生变化SELECT MAX(updated_at)的查询结果就会改变缓存随即失效。从源码看DbDependency在执行 SQL 时会临时关闭并恢复数据库的查询缓存enableQueryCache确保依赖检测读到的是最新数据并通过sqlparams绑定参数而Dependency基类提供了reusable静态缓存机制同一依赖在一次请求内可避免重复计算。依赖对象是在写入缓存时由配置数组经Yii::createObject()创建并随缓存数据一同存储的见FragmentCache::run()。variations缓存变体被缓存的内容可能随某些参数而发生变化。例如对于支持多语言的 Web 应用同一段视图代码可能生成不同语言的内容因此你可能希望缓存内容随当前应用语言而变化。设置缓存变体时使用variations选项它应是一个标量值数组每个值代表一个特定的变化因素。例如让缓存内容随语言变化if ($this-beginCache($id, [variations [Yii::$app-language]])) { // ...在这里生成内容... $this-endCache(); }从源码看FragmentCache::calculateKey()会把variations合并进缓存键array_merge([__CLASS__, $this-getId()], (array)$this-variations)。也就是说variations并不是对同一份内容做覆盖而是通过不同的缓存键天然生成多份独立缓存不同语言或不同 GET 参数、不同用户分组等互不干扰。数组型缓存键最终会由Cache::buildKey()序列化并 MD5 哈希后使用若键为 32 字符以内的纯字母数字字符串则直接使用因此可以放心把语言代码等值传入。enabled按条件开关缓存有时你只想在满足特定条件时启用片段缓存。例如对于展示表单的页面你只希望在表单初次请求GET 请求时缓存它而后续的 POST 请求显示不应被缓存因为表单中可能包含用户输入。为此可设置enabled选项if ($this-beginCache($id, [enabled Yii::$app-request-isGet])) { // ...在这里生成内容... $this-endCache(); }当enabled为false时内容生成逻辑每次都执行既不读缓存也不写缓存。源码中这一行为的实现是FragmentCache::init()中cache属性会在enabled为假时被置为null从而跳过缓存的读取与写入见FragmentCache::init()。嵌套缓存片段缓存可以嵌套即一个被缓存的片段可以包含在另一个同样被缓存的片段之中。例如评论被缓存在内层片段缓存中同时评论与文章内容一起被缓存在外层片段缓存中。下面展示两个片段缓存如何嵌套if ($this-beginCache($id1)) { // ...内容生成逻辑... if ($this-beginCache($id2, $options2)) { // ...内容生成逻辑... $this-endCache(); } // ...内容生成逻辑... $this-endCache(); }不同的缓存选项可以为嵌套缓存分别设置。例如内层缓存与外层缓存可以使用不同的duration值。嵌套缓存的失效行为有一个重要规律即使外层缓存中的数据失效内层缓存仍可能提供有效的内部片段反过来则不成立——如果外层缓存被判定为有效即使内层缓存内容已失效外层仍会继续提供同一份缓存副本。因此设置嵌套缓存的duration或dependency时必须谨慎否则过期的内部片段可能被长期保留在外层片段中。动态内容缓存中永不失效的部分使用片段缓存时你可能会遇到这种情况一个很大的片段内容大部分相对静态只有一两处是动态的。例如页面头部可能同时显示主菜单栏和当前用户名。另一个常见问题是被缓存的内容里可能包含必须每次请求都执行的 PHP 代码例如注册资源包的代码。这两个问题都可以通过所谓的动态内容功能解决。动态内容指的是输出中即使被包含在片段缓存内也永不缓存的部分。为了让它始终保持动态即使外层内容正从缓存中提供服务这部分也必须在每次请求时通过执行 PHP 代码生成。你可以在被缓存的片段内调用yii\base\View::renderDynamic()在期望的位置插入动态内容如下所示if ($this-beginCache($id1)) { // ...内容生成逻辑... echo $this-renderDynamic(return Yii::$app-user-identity-name;); // ...内容生成逻辑... $this-endCache(); }renderDynamic()方法接受一段 PHP 代码作为参数PHP 代码的返回值被当作动态内容。无论外层片段是否从缓存中提供这段 PHP 代码都会在每次请求时执行。动态内容的底层原理动态内容并非把 PHP 代码存进缓存、每次重新执行那么简单而是采用「占位符 回填」机制可以从源码中清晰看到写入阶段在缓存未命中、开始捕获输出时renderDynamic()检测到当前存在激活的内容缓存栈cacheStack于是生成形如![CDATA[YII-DYNAMIC-0]]的占位符替换动态内容并把「占位符 → PHP 代码」的映射记录到DynamicContentAwareTrait::addDynamicPlaceholder()中随后FragmentCache::run()把[$content, $placeholders]二元组存入缓存。读取阶段命中缓存后FragmentCache::getCachedContent()从缓存恢复内容与占位符映射再调用updateDynamicContent()——由于此时缓存栈已空处于最外层缓存占位符会被eval执行 PHP 代码后的真实结果通过strtr()替换见DynamicContentAwareTrait::updateDynamicContent()。多层嵌套场景updateDynamicContent()会检查getView()-getDynamicContents()是否为空只有最外层缓存才执行占位符替换从而保证嵌套缓存中的占位符能被正确逐层保留与回填。自 2.0.14 起动态内容 API 通过yii\base\DynamicContentAwareInterface接口及其yii\base\DynamicContentAwareTraittrait 对外暴露yii\widgets\FragmentCache类即实现了该接口并使用该 trait见FragmentCache.php页面缓存等其他缓存形式同样可以复用这套机制。源码视角FragmentCache 组件的工作流程综合以上分析一次完整的片段缓存生命周期如下对应 FragmentCache 源码View::beginCache($id, $options)以FragmentCache小部件形式启动init()中将cache属性解析为缓存组件实例若enabled为假则置null直接跳过后续步骤。若缓存中不存在有效内容getCachedContent()返回falseinit()会把该片段压入视图的cacheStack并开启输出缓冲ob_start()返回true让视图继续生成内容。视图内容生成完毕调用View::endCache()→FragmentCache::run()取出输出缓冲内容把依赖配置数组实例化为依赖对象将[$content, $placeholders]连同duration、dependency写入缓存组件最后回填动态内容并输出。后续请求再次命中缓存时getCachedContent()直接返回替换好动态内容的缓存副本beginCache()立即返回false。其中缓存键由calculateKey()统一生成删除缓存时按「片段 ID 变体」即可精确操作缓存组件本身支持前缀keyPrefix、序列化serializer等配置见Cache基类。测试验证仓库中 tests/framework/widgets/FragmentCacheTest.php 对片段缓存的核心行为提供了完整验证可作为理解本文内容的最佳对照testCacheEnabled第一次beginCache(test)返回true输出内容写入缓存第二次同一 ID 返回false且直接输出缓存的cached fragment验证了命中与未命中两种分支testCacheDisabled1/testCacheDisabled2验证enabled false时始终不读写缓存、内容每次重新生成testSingleDynamicFragment等动态内容用例验证renderDynamic()中的 PHP 代码在缓存命中后依然每次执行且计数自增结果正确回填到缓存内容中用例中Yii::$app-params[counter]在 42 次循环中逐次递增。这些测试同时确认了输出缓冲在启用/禁用缓存两种路径下都能被正确闭合不会产生缓冲区泄漏。使用建议综合文档与源码使用片段缓存时有几点值得注意优先缓存「重」片段适合把生成开销大、更新频率低的内容汇总报表、文章详情、菜单列表放入片段缓存避免为轻量输出引入额外的缓存读写开销合理组合依赖与有效期数据变更频繁的内容优先用dependency保证一致性变更缓慢的内容用duration控制过期即可多语言/多参数站点务必配置variations否则不同语言或不同筛选条件下的用户会共享同一份缓存内容嵌套缓存要警惕内层失效问题如文档所述外层缓存有效时内层已失效的片段仍会被整体输出需要统一协调内外层的duration与dependency动态内容用renderDynamic()把「必须每次执行」的代码当前用户信息、资源包注册放入renderDynamic()其余静态部分照常缓存。至此从基本用法、四大缓存选项、嵌套缓存到动态内容的完整片段缓存体系已经梳理完毕。你可以结合 数据缓存、页面缓存 与视图文档在项目中搭建起从数据层到视图层的完整缓存方案。【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

微信用英语怎么说?后端开发最佳实践避坑指南

微信用英语怎么说?后端开发最佳实践避坑指南

微信用英语怎么说?后端开发最佳实践避坑指南 复制来的代码跑不通不知道怎么调,这是很多刚接触国际化(i18n)模块的开发者最头疼的事。别慌,这不是你的代码写得烂,而是你没搞懂 最佳实践 里的上下文隔离机制。今天我们就把 微信用英语怎么说…

2026/9/23 6:23:04 阅读更多 →
搞懂安卓ios模拟器:3个主流方案深度对比+完整示例

搞懂安卓ios模拟器:3个主流方案深度对比+完整示例

搞懂安卓ios模拟器:3个主流方案深度对比+完整示例 你是不是也这样?看了一堆关于安卓ios模拟器的教程,视频里跑得飞起,自己一动手就卡壳。想写个自动化脚本,或者搞个多开测试,结果环境配置搞了三天,还是报错。别急,今天不整虚的,直接上干货。…

2026/9/23 6:22:04 阅读更多 →
53货源网官网手写实现速查手册

53货源网官网手写实现速查手册

53货源网官网手写实现速查手册 面试被问原理答不上来,简历写满项目却讲不清底层逻辑,这种尴尬谁没经历过?别慌,这份 53货源网官网 核心模块的 速查手册…

2026/9/23 6:22:04 阅读更多 →

最新新闻

PN532 NFC模块实战:从硬件连接到读写卡片的完整指南

PN532 NFC模块实战:从硬件连接到读写卡片的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/23 7:41:21 阅读更多 →
Comsol管内两相流模拟:从泡状流到弹状流的工程实践

Comsol管内两相流模拟:从泡状流到弹状流的工程实践

1. 项目概述:管内两相流模拟的工程价值在石油化工、核能发电等工业场景中,管道内气液两相流动的精确模拟一直是工程师面临的经典难题。去年我在参与某海上平台油气输送系统改造时,就曾因低估了弹状流对管道的冲击振动,导致不得不返…

2026/9/23 7:41:21 阅读更多 →
IP5306 I2C通信失效根因与鲁棒设计实战

IP5306 I2C通信失效根因与鲁棒设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/23 7:41:21 阅读更多 →
光储一体化系统设计与优化关键技术解析

光储一体化系统设计与优化关键技术解析

1. 光储设计一体化系统概述光储设计一体化系统是近年来新能源领域的重要技术突破,它将光伏发电与储能系统深度融合,形成一个高效、稳定的能源供应单元。这种系统不同于传统的光伏发电与储能设备简单并联的模式,而是从设计阶段就将两者视为有机…

2026/9/23 7:41:21 阅读更多 →
赵奕欢博客搭建避坑指南:3步搞定性能优化最佳实践

赵奕欢博客搭建避坑指南:3步搞定性能优化最佳实践

赵奕欢博客搭建避坑指南:3步搞定性能优化最佳实践 配置环境就卡半天?别急,这真不是你的错。很多刚接触 赵奕欢博客 系统的朋友,都卡在服务器环境配置和依赖库冲突上,折腾一整天连个静态页面都跑不起来。其实,只要掌握 最佳实践…

2026/9/23 7:41:21 阅读更多 →
自带鼠标驱动的BIOS隐藏选项修改工具实战

自带鼠标驱动的BIOS隐藏选项修改工具实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/23 7:40:20 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/22 8:51:04 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →