ThinkPHP 6 配置加载严格按 config/autoload/ 下子目录优先级:think(最低)、app、env(最高);自定义配置须放 autoload/ 子目录(如 custom/),根目录文件不加载;.env 仅覆盖 env/ 下同名配置;Config::set() 在中间件中失效因 Db 等组件缓存初始配置,应改用 Db::setConfig() 或提前设置。

ThinkPHP 6 的配置加载顺序到底是怎样的
自定义配置不生效,八成是被后加载的配置覆盖了。TP6 不再按文件名顺序加载,而是严格按 config/autoload 目录下各子目录的优先级来:系统默认配置(think)最低,应用配置(app)次之,环境配置(env)最高;而你放错位置的 my_config.php 如果扔在 config/ 根目录,它压根不会被自动加载。
实操建议:
- 所有自定义配置必须放在
config/autoload/下的某个子目录里,比如新建config/autoload/custom/,再把database.php放进去 - 环境配置(如
.env)会覆盖 PHP 配置里的同名键,但只作用于env目录下的配置文件,对custom目录无效 -
config/app.php是硬编码入口配置,它本身不参与 autoload 机制,修改它要重启服务(Swoole 场景下尤其注意)
为什么 Config::set() 在中间件里失效
因为 TP6 的配置对象是「请求生命周期内单例」,但 Config::set() 只影响当前实例,而路由调度、中间件、控制器可能拿到的是不同上下文里的配置副本——尤其开启多应用或使用 think-middleware 插件时。
常见错误现象:
立即学习“PHP免费学习笔记(深入)”;
- 在中间件里调用
Config::set('database.hostname', '127.0.0.2'),控制器里读出来还是旧值 - 用
config('database.hostname')能读到新值,但Db::connect()连的仍是旧库
原因在于 Db 类在第一次调用时就缓存了连接配置,后续不再读取 Config 实例。正确做法是提前设置,或强制重载:
使用ydata-profiling(前身为pandas-profiling)生成全面的数据质量报告,包含相关性分析、缺失值模式和基数检测。导出交互式HTML仪表板和JSON摘要。
- 在
app/bootstrap.php或public/index.php中调用Config::set(),确保早于任何 Db 初始化 - 若必须运行时切换,用
Db::setConfig()替代Config::set(),它会同步刷新连接池 - 避免在中间件中修改全局配置,优先走参数传入,比如
Db::connect(['hostname' => 'xxx'])
升级 TP6.3 后 extra_config_list 不再生效
这个配置项在 TP6.2 里还能用,6.3 开始被移除,文档没明说,但源码里 think\Config 的 loadAll() 方法已删掉对它的解析逻辑。强行保留会导致配置漏载,且无任何报错提示。
替代方案很简单,但容易忽略路径细节:
- 把原来写在
config/app.php里的'extra_config_list' => ['my_api', 'pay']拆成两个文件:config/autoload/custom/my_api.php和config/autoload/custom/pay.php - 确保
custom目录在config/autoload/下,而不是config/根目录——后者不会被扫描 - 如果用了 Composer 自动加载(如
think-swoole),还要检查composer.json的autoload.files是否误加了配置文件,会导致重复加载冲突
多环境部署时 .env 和 PHP 配置的优先级陷阱
.env 文件只影响 env 目录下的 PHP 配置,比如 config/autoload/env/database.php,但它不会穿透到 custom 或 app 目录。很多人把数据库密码写进 .env,却在 custom/database.php 里硬编码 'password' => '123456',结果环境变量根本不起作用。
性能与兼容性提醒:
-
.env解析发生在请求早期,但每次请求都重新读取文件(除非启用 OPcache +opcache.file_cache),高并发下有 I/O 开销 - 如果
.env里写了APP_DEBUG=true,而config/autoload/app.php里又设了'debug' => false,最终以app.php为准——因为app目录优先级高于env - CI/CD 自动注入环境变量时,别直接覆盖
.env,推荐用putenv()注入,再让 TP 通过Env::get()读取,更可控
最常被跳过的一步:改完配置后忘记清空 runtime/config/ 缓存,尤其是启用了 config_cache 的生产环境。缓存不清理,怎么改都不生效。


















