模板变量替换与布局继承是独立机制,前者作用于渲染前的html字符串,后者发生在编译期;{extend}必须严格位于子模板首行首字符,否则继承静默失效。

模板变量替换和布局继承是两套独立机制,不能混用逻辑;变量替换发生在渲染前,布局继承发生在编译期——写错顺序或误以为它们自动联动,是 90% 的“页面空白”“内容不显示”问题根源。
模板变量替换只对 fetch() 渲染的内容生效,不触发布局逻辑
ThinkPHP 的变量替换(如 $this->view->filter() 或配置中的 template.replace_string)作用对象是最终输出的 HTML 字符串,不是模板文件本身。它不会识别 {extend}、{block} 等语法,也不会修改布局加载行为。
- 如果你在
filter回调里尝试匹配{__CONTENT__}并替换,会失败——因为此时布局还没开始编译,该字符串根本不存在 -
filter只能处理控制器通过assign()传入、且在模板中显式输出的变量,比如{$name}→ 被替换成“刘德华” - 若模板中写了未赋值的
{$undefined},filter还没执行,模板引擎就已报错中断,根本走不到替换环节
{extend} 必须首行无任何字符,否则整个继承链静默失效
这是最常被忽略的硬性规则:{extend name="public/base"} 必须严格位于子模板文件第一行、第一个字符位置。前面多一个空格、空行、BOM 头、PHP 注释,都会导致 ThinkPHP 完全跳过继承逻辑,直接渲染子模板原始内容。
- 现象:页面只显示子模板里的文字,没有 header、footer、title —— 查看源码开头就是
<div>主体</div>,说明{extend}没被识别 - 路径
name值不带后缀,也不加.html;它相对于view_path配置,比如view_path = 'app/view/',那么name="public/base"对应的是app/view/public/base.html - 父模板里必须存在同名
{block name="xxx"},否则子模板的{block name="xxx"}会被直接丢弃,不报错、不警告、不渲染
{block} 是完全替换,想保留父内容得用 {__BLOCK__}
{block} 不是占位符,而是“声明式覆盖区”。父模板中 {block name="script"}<script>init();</script>{/block},子模板写 {block name="script"}<script>loadMore();</script>{/block},结果只有 loadMore(),init() 彻底消失。
- 要追加 JS,父模板必须写成
{block name="script"}{__BLOCK__}<script>init();</script>{/block} -
{__BLOCK__}是唯一能插入子模板对应 block 内容的标记,大小写敏感,不能写成{__block__}或{_BLOCK_} - 不支持嵌套
{block}中再用{__BLOCK__}引用更上层内容;A 继承 B、B 继承 C,A 只能覆盖 B 显式透传的 block,无法直触 C
缓存不清理,改了配置或模板也白搭
ThinkPHP 编译后的模板缓存在 runtime/template/ 下,文件名含哈希。哪怕你改对了 {extend} 语法、配好了 layout_on,只要缓存没清,旧的错误编译结果就会一直生效。
- 开发阶段务必删掉
runtime/template/全部内容再刷新,不要只删某个文件 - 配置项如
layout_name或layout_item修改后,必须清缓存,否则仍按旧规则解析 - 用
php think clear命令可一键清空,但注意它默认不清 template 缓存,需加--template参数
真正卡住人的从来不是语法记不住,而是“以为生效了”——比如看到子模板里写了 {extend} 就觉得布局肯定起了作用,结果它从第一行起就没被 parser 扫到。打开浏览器开发者工具看 HTML 源码,开头是不是 layout 里的 ?不是,就别往下调样式了,先查那第一行。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











