首页/新闻资讯/正文详情

Yii 2 片段缓存(Fragment Caching)完全指南:从基本用法到嵌套缓存与动态内容

发布时间:2026/9/23 6:23:09 来源:云帆数科 栏目:资讯中心
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:09

Agent技能化实战:从工具封装到技能包管理的完整指南
Agent技能化实战:从工具封装到技能包管理的完整指南

最近几个月,“agent-skills”这个词在我待的几个技术讨论群里出现频率明显变高了。一开始我以为又是哪个新框架的宣传话术,点进去仔细看了几轮讨论,才意识到大家其实在聊一个很实在的问题:大模型Agent的能力到底应该怎么封装、怎么… · 2026/9/23 6:23:09

81年今年多大?从年龄算法看代码避坑指南
81年今年多大?从年龄算法看代码避坑指南

81年今年多大?从年龄算法看代码避坑指南 刚写完一个生日计算功能,测试环境全绿,上线后却被用户投诉算错了。这种“学会语法却不知怎么搭项目”的尴尬,在开发中太常见了。很多人盯着 new Date()… · 2026/9/23 6:23:09

ThinkPHP5架构深度拆解:从自动加载到中间件的核心机制解析
ThinkPHP5架构深度拆解:从自动加载到中间件的核心机制解析

1. TP5 整体架构设计思路聊 TP5(ThinkPHP 5)之前,我翻了翻以前的项目代码,从 TP3.2 一路用到 TP6,中间确实感慨挺多。TP5 这个版本在 ThinkPHP 家族里算是个分水岭,它不像 TP3 那样靠一大堆函数和 import 机… · 2026/9/23 10:57:13

C# ONNX实现P2PNet人群计数:密度图+点回归+软聚类全链路解析
C# ONNX实现P2PNet人群计数:密度图+点回归+软聚类全链路解析

简介:本资源是基于C#与ONNX Runtime实现的P2PNet人群检测与计数完整工程,面向具备基础C#开发能力及计算机视觉兴趣的中高级开发者,解决安防监控、客流统计、公共空间人流量分析等实际场景中的密集人群定位与精准计数问题。压缩包共77个文件&a… · 2026/9/23 10:57:13

ETTh1时间序列预测实战:LSTM、Transformer与线性模型全链路复现
ETTh1时间序列预测实战:LSTM、Transformer与线性模型全链路复现

简介:本资源是一套面向计算机及相关专业(如人工智能、数据科学、自动化等)在校学生与初阶研究者的ETTh1时间序列预测实践项目,聚焦毕业设计、课程设计与大作业场景,提供LSTM、Transformer及自定义线性模型三种主流方案… · 2026/9/23 10:57:13

遥感电塔检测数据集详解:VOC与YOLO双格式解析及YOLOv8训练实践
遥感电塔检测数据集详解:VOC与YOLO双格式解析及YOLOv8训练实践

简介:面向遥感目标检测任务的数据集资源,聚焦电塔目标识别场景,适合需要训练或微调电塔检测模型的算法工程师、研究人员及学习者使用。资源采用Pascal VOCYOLO双格式存放,包含244张jpg原图、244个xml标注文件与244个txt标注文件&a… · 2026/9/23 10:57:06

苹果十开发入门到精通:面试原理避坑指南
苹果十开发入门到精通:面试原理避坑指南

苹果十开发入门到精通:面试原理避坑指南 面试时被问“苹果十”底层机制,你只能支支吾吾说“就是个版本号”?这直接导致项目黄了。很多开发者把【苹果十】当成一个模糊的概念,导致在实战中反复踩坑,无法从 入门到精通… · 2026/9/23 10:57:06

告别官方文档坑:3行代码手写实现免费图高性能渲染
告别官方文档坑:3行代码手写实现免费图高性能渲染

告别官方文档坑:3行代码手写实现免费图高性能渲染 别再去翻那几百页的官方文档了,抓不住重点还容易看晕。很多团队在加载免费图资源时,性能瓶颈往往不在网络,而在解码与重绘。 手写实现 一个轻量级的图片加载与缓存模块,往往比引入重型框架更高效。… · 2026/9/23 10:57:06

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

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

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码