ROOT 是通过 template 配置项中的 tpl_replace_string 实现的静态文本替换,需手动配置 ['__ROOT__' => ROOT_PATH],不走 PHP 常量解析,不可与 {$Think.const.__ROOT__} 混用。

ThinkPHP 模板中 __ROOT__ 这类常量怎么配出来
直接说结论:__ROOT__ 不是框架内置“硬编码”的模板变量,而是靠 tpl_replace_string 配置项在模板编译阶段做字符串替换实现的。它不走 PHP 常量解析,也不进 $Think.const,所以不能用 {$Think.const.__ROOT__} —— 那样会报错或为空。
实操上,你得在 config.php 的 template 配置块里手动加这一行:
'tpl_replace_string' => ['__ROOT__' => ROOT_PATH],
注意两点:
-
ROOT_PATH是 ThinkPHP 启动时定义的 PHP 常量(如/var/www/html/),不是字符串"ROOT_PATH" - 这个替换发生在模板文件被读取后、编译成 PHP 缓存文件之前,属于纯文本替换,不涉及运行时上下文
tpl_replace_string 和 $Think.const 的区别在哪
这是最容易混淆的点:一个走编译期文本替换,一个走运行时常量反射。
比如你想在模板里用 {$Think.const.MAXONLINETIME},那必须先在 PHP 代码里定义 define('MAXONLINETIME', 3600);而 __ROOT__ 这种,哪怕你没 define(),只要 tpl_replace_string 配了,模板里写 __ROOT__/static/js/app.js 就能直接变成 /var/www/html/static/js/app.js。
关键差异:
-
tpl_replace_string:只支持字符串 → 字符串映射,不能调函数、不能拼接、不感知作用域 -
$Think.const.xxx:依赖 PHPdefine()或const,可动态计算,但模板里访问慢一点(要反射) - 二者不互通——
tpl_replace_string里填['__ROOT__' => defined('ROOT_PATH') ? ROOT_PATH : '']是无效的,因为替换发生时 PHP 常量还没被读取到模板上下文
为什么改了配置模板里还是不生效
常见原因就三个,按优先级排查:
- 没清模板缓存:ThinkPHP 默认开启
tpl_cache,改完配置后旧的编译文件还在runtime/template/下,删掉整个目录最干脆 - 配置位置错了:必须塞在
'template' => [ ... ]数组内部,不能挂在根配置层,也不能写在view或app分组里 - 路径值带斜杠尾巴:比如
ROOT_PATH结尾是/,而你的静态资源路径又写了__ROOT__/css/app.css,结果变成//css/app.css—— 浏览器可能 404,建议统一用rtrim(ROOT_PATH, '/')处理
能不能在模板里动态拼接路径,比如 __ROOT__/theme/{$theme}/style.css
不能。因为 tpl_replace_string 是纯静态替换,不解析任何模板语法。上面这行里的 {$theme} 在替换阶段还没执行,所以 __ROOT__ 会被替换成真实路径,但 {$theme} 还原封不动留在输出里,最终浏览器拿到的是类似 /var/www/html/theme/{$theme}/style.css 这种非法路径。
正确做法只有两个:
- 把完整路径提前算好,assign 进模板:
$this->assign('css_url', __ROOT__ . '/theme/' . $theme . '/style.css');,然后模板里用{$css_url} - 改用
$Think.const+ 自定义常量,比如define('THEME_URL', __ROOT__ . '/theme/' . $theme);,再配tpl_replace_string映射__THEME__—— 但注意:这种写法要求$theme在常量定义时就是确定值,不能随请求变化
真正灵活的路径组装,终究得回到 PHP 层控制,模板里只负责“展示”,别让它承担“计算”任务。










