config()读到的值优先来自.env,其次为运行时设置、config/*.php文件、框架默认值;.env中DB_HOST等键会完全覆盖config/database.php对应项,但需确保正确加载且runtime/config.php缓存已清。

config() 读到的值到底来自 .env 还是 config/*.php?
直接看 config() 返回值不能判断来源,必须查加载优先级链路。ThinkPHP 配置生效顺序固定为:.env 环境变量 > 运行时 config() 动态设置 > config/*.php 文件 > 框架默认值。这意味着只要 .env 里定义了 DB_HOST,哪怕 config/database.php 写了 'hostname' => '10.0.0.1',最终 config('database.hostname') 也一定是 .env 里的值。
验证方法:在控制器里加两行:
dump(env('DB_HOST'));<br>dump(config('database.hostname'));
如果两者一致,说明 .env 覆盖成功;如果不一致,大概率是 .env 根本没加载,或键名写错(比如写了 db_host 而非 DB_HOST)。
为什么 dump(config('database.hostname')) 显示旧值?
常见原因不是配置没覆盖,而是缓存锁住了旧值。ThinkPHP 在 app_debug = false 时会把合并后的全部配置写入 runtime/config.php,后续请求直接读这个文件,跳过所有源文件解析。
立即学习“PHP免费学习笔记(深入)”;
-
runtime/config.php存在且非空 → 框架走缓存路径,改.env或config/*.php都不生效 -
runtime/config.php为空或语法错误 → 框架静默 fallback 到原始加载流程,但可能漏读部分配置(比如只加载了config/app.php,没进config/prod/目录) -
APP_DEBUG=true但config()仍不更新 → 检查是否被 OPcache 锁住字节码,需重载 PHP-FPM 或执行opcache_reset()
env() 和 config() 返回 null 或默认值,怎么定位源头?
先绕过 ThinkPHP 封装,直查 PHP 底层环境变量:
在 public/index.php 顶部插入:
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__.'/..');<br>$dotenv->safeLoad();<br>var_dump($_ENV['DB_HOST'] ?? 'not in $_ENV');<br>var_dump(getenv('DB_HOST') ?: 'not in getenv');<br>exit;
结果分三种情况:
- 两个都为空 →
.env文件没加载(路径错、权限不够、文件名带 BOM 或扩展名) - 其中一个有值 →
env()封装层出问题(比如think-env扩展未启用,或variables_order里没含E) - 两个都有值但
config()不一致 → 说明config/database.php里没用env('DB_HOST'),而是写了死值,或者该配置项根本不在config()合并路径里(比如你改的是config/dev/database.php,但当前APP_ENV=prod)
多环境目录(config/dev/、config/prod/)下配置被覆盖的边界在哪?
.env 只覆盖「已声明」的键,不会自动注入新键。例如:
-
config/prod/database.php里写'hostname' => env('DB_HOST', '192.168.1.100')→.env中DB_HOST会生效 -
config/prod/database.php里写'hostname' => '192.168.1.100'(没包env())→.env中DB_HOST完全无效 -
.env里写了REDIS_HOST=127.0.0.1,但config/prod/cache.php里压根没提REDIS_HOST→ 这个变量存在$_ENV里,但config('cache.redis.host')仍为 null
真正容易被忽略的是:框架不会帮你“猜”变量用途,.env 的值只有被 env() 显式调用、且该调用出现在某份正在加载的配置文件中,才会进入最终 config() 结果。



















