必须将 helper.php 放在 app/helper.php 路径,开头加 function_exists() 判断,composer.json 中 autoload.files 仅配置 "app/helper.php" 并执行 composer dump-autoload,最后通过函数存在性验证生效。

要在 ThinkPHP 8.0 中让自定义函数在控制器、模型、中间件甚至命令行脚本里随处可用,必须绕过框架“不鼓励全局函数”的默认倾向,严格匹配 Composer 自动加载机制与文件路径规范,否则函数永远无法被识别。
第一步:把 helper.php 放对位置
ThinkPHP 8.0 只认 【app/helper.php】 这一个路径——不是 app/common/helper.php,也不是 app/extend/helpers.php,更不能是 app/helpers/helper.php。文件名必须是 helper.php(单数),且必须直接放在 app 目录下。
执行命令确认路径真实存在:ls -l app/helper.php。如果返回“No such file”,立刻创建它;如果显示的是 app/Helper.php 或 app/Helpers/helper.php,说明大小写或层级错了,删掉重来。
第二步:写函数前先加防重声明
在 app/helper.php 开头第一行就写:if (!function_exists('my_log')) {,然后才定义函数体,末尾补上 }。所有函数都必须套这层判断。
立即学习“PHP免费学习笔记(深入)”;
不加 function_exists() 的后果很直接:Laravel 或其他扩展包自带的 helpers.php、PHP 8.1 新增的 str_starts_with()、甚至 tp8 内置的 success() 都可能和你的函数同名,一旦触发 Fatal error: Cannot redeclare,错误堆栈会指向 vendor/composer/ClassLoader.php,根本看不出是你写的函数惹的祸。
这一步操作起来很简单,但跳过就会导致整个应用启动失败。
第三步:确保 composer.json 已声明该文件
打开项目根目录下的 composer.json,找到 autoload → files 数组,确认里面只有且仅有这一行:"app/helper.php"。
常见错误包括:路径写成 ./app/helper.php(开头的 ./ 会导致 Linux/macOS 下静默失效)、写成 app/Helper.php(大小写错)、或多写了其他路径如 "app/common/functions.php"(TP8 不支持额外路径)。
改完后必须立即执行:composer dump-autoload。这一步不可跳过,否则修改了 composer.json 也白改——autoload_files.php 不会自动更新,函数永远不会被 require_once。
第四步:验证是否生效
方法一:在任意控制器的 action 里写 return my_log('test');,访问对应路由。如果返回内容或抛出 “Call to undefined function” 错误,说明前三步至少有一处没做对。
方法二:在命令行运行 php think run 启动内置服务器后,再新开终端执行 php -r "var_dump(function_exists('my_log'));"。返回 true 才算真正挂载成功。
注意:如果你在 public/index.php 之外的入口文件(比如自己写的 CLI 脚本)里调用,必须手动引入 require __DIR__.'/../vendor/autoload.php';,否则函数不可见。



















