编译流程与缓存 Compile Cache
DouView 是「按需编译 + 落盘缓存」的引擎:模板源只在必要时编译一次,产物写入编译目录,之后直接 include 执行。理解缓存的失效判据,能避免「改了模板不生效」「切了主题串页」这类问题。
一、渲染一个模板的完整流程
DouView::renderResource($resourceName) 的执行步骤:
1. resolveTemplatePath:把资源名解析为绝对路径(扩展名白名单 + 路径穿越/越界校验)
2. compilePath:算出该资源对应的编译产物路径
3. needsRecompile:判断是否需要重编(见下)
4. 若需要:读源 → runPrefilter → compile → 写入编译产物
5. include 编译产物(配合 RenderContext 输出)
二、是否需要重编(needsRecompile)
编译缓存的有效性由三个判据共同决定:
| 判据 | 行为 |
|---|---|
force_compile = true |
每次请求都重编,忽略缓存(调试用,生产环境有性能代价) |
| 编译产物不存在 | 首次访问必然重编 |
COMPILE_REVISION 版本头不匹配 |
编译产物头部写入修订号,与引擎常量不一致则重编 |
compile_check = true 且源 mtime 更新 |
源文件比编译产物新,则重编 |
其中 compile_check 默认为 true:开发期改完模板刷新即可生效;生产环境若追求极致性能可置 false,但那样改模板后必须手动清缓存。
三、COMPILE_REVISION —— 引擎级失效开关
DouView::COMPILE_REVISION(当前为 11)是一个「编译修订号」,与产品版本 VERSION(1.0)无关,专门用作缓存失效判据:
- 每当编译语义或 Prefilter 行为发生变化,开发者会 bump 这个常量;
- 旧编译产物头部的 rev 与新常量不一致,
needsRecompile返回真,全部模板自动重编; - 这保证了「引擎升级后无需手动清缓存也不会用旧语义渲染」。
四、前台的特殊性:theme_path 字面烘焙
前台预过滤器(FrontPrefilter)会在编译期把运行期的主题绝对路径字面烘焙进编译源——也就是说,编译产物里直接写死了当前主题的静态资源绝对路径。由此产生两个必须记住的结论:
- 编译缓存与主题强绑定:同一模板在不同主题下编译出的产物不同;
- 切主题 / 升级引擎后必须清缓存:切换站点主题时,系统会自动清理模板编译缓存(配合
COMPILE_REVISION失效),否则可能渲染出旧主题的资源路径。
五、实践建议
- 开发调试:保持
compile_check = true,改模板即时生效;若怀疑缓存串味,清空编译目录(compile_dir,默认templates_c)后重试。 - 上线部署:切换主题、覆盖模板文件、升级引擎后,清一次编译缓存最稳妥。
- 排查「模板改了不生效」:依次确认——① 改的是当前生效主题下的文件;②
compile_check是否被关掉;③ 编译目录是否可写、是否残留旧产物。