配置读取慢的根源是config()每次重新include所有配置文件,解决方法为关闭APP_DEBUG、运行optimize:config生成缓存文件、避免点号嵌套访问。

配置读取慢,不是 PHP 解析慢,而是 config() 每次都重新 include 所有配置文件 —— 关键在关掉 APP_DEBUG、跑 optimize:config、避免点号嵌套访问。
为什么 config() 每次都重新解析配置文件
ThinkPHP 默认不启用配置编译缓存,尤其当 APP_DEBUG = true 时,optimize:config 命令被跳过,config() 就只能每次请求都 include app.php、database.php 等一堆文件。这不是 bug,是开发模式下的主动降级设计。
常见错误现象:strace -e trace=openat php think hello 可看到大量重复 open 配置文件操作;Xdebug profile 显示 think\facade\Config::get 占用显著 CPU 时间。
- 检查当前值:
var_dump(config('app_debug'));或看.env里APP_DEBUG=true - 生产环境必须设为
false,否则缓存机制形同虚设 - CLI 脚本可单独控制:运行前加
APP_DEBUG=false php think optimize:config
怎么生成并启用配置缓存文件
运行 php think optimize:config 后,框架会把 config/ 下所有 PHP 配置文件合并为单个 runtime/cache/config.php,后续请求直接 include 这一个文件,省去路径查找、多次解析、重复 require 的开销。
立即学习“PHP免费学习笔记(深入)”;
- 确保
runtime/cache/目录存在且 Web 进程可写,否则命令静默失败,config.php不生成 - 合并后
config()仍可用,但内部逻辑已切换为读取缓存文件 + 数组查找 - 修改配置后需手动重跑该命令,它不会自动监听文件变更
- 若用 CI/CD,建议在部署脚本末尾加入
php think optimize:config
点号嵌套键(如 database.connections.mysql.host)为什么慢
即使启用了配置缓存,config('database.connections.mysql.host') 仍比 config('db_host') 慢 2–3 倍 —— 因为框架要对字符串做 explode('.', $key),再逐层递归数组访问,无法利用 PHP 的哈希表 O(1) 查找。
- 避免在循环或高频路径中使用带点号的键,例如不要写
foreach (config('database.connections') as $name => $conf) - 初始化阶段(如
app/common.php)提前提取扁平常量:define('DB_HOST', config('database.connections.mysql.host')); - 需要运行时切换的场景才用
Config::set(),它改的是内存数组,不写回缓存文件,重启即丢 - CLI 场景若只读几个配置项,可直接
require runtime/cache/config.php后提取变量,绕过config()函数层
define() 和 Config::set() 性能与作用域差异
define() 是 PHP 编译期常量,零运行时开销;Config::set() 是框架维护的动态数组,每次 config() 调用都要查这个数组,还涉及键标准化(如大小写转换、点号转下划线)。
- 绝对不变的值(如
API_SECRET、ENCRYPT_SALT)必须用define(),之后直接用常量名,不走任何函数调用 - 多租户 DB 切换、灰度开关等需运行时覆盖的,才用
Config::set(),但注意它不持久化,也不能跨进程生效 - 别在控制器方法里反复调用
config('xxx'),应提取到属性或局部变量中复用
最易被忽略的一点:缓存文件生成后,如果 runtime/cache/config.php 权限不对(比如属主是 root),Web 进程无法读取,就会退回到原始多文件 include 模式 —— 表现就是“明明跑了 optimize:config,但还是慢”,务必检查该文件的实际可读性。



















