ThinkPHP 默认仅在应用初始化早期自动加载 .env 文件,且需满足 APP_ENV 未被外部定义、.env 位于入口同级目录、无空格格式正确等条件;变量需匹配白名单前缀并区分大小写,配置占位符仅在加载阶段解析,Swoole 等长生命周期场景须主进程预加载。

ThinkPHP 读不到 .env 文件里的变量?先看加载时机
ThinkPHP 默认只在应用初始化早期自动加载 .env,且仅当 APP_ENV 未被外部定义(如 CLI 环境下通过 export APP_ENV=dev)时才生效。一旦 PHP 进程启动后手动改写 $_ENV 或 $_SERVER,ThinkPHP 不会重新解析 .env。
- 确认
.env文件位于入口文件(如public/index.php)同级目录,不是放在app/或config/下 - 检查
index.php是否调用了think\Env::load()—— 5.1+ 版本通常已内置,但自定义入口或 Swoole 场景下可能被跳过 -
.env中等号两侧不能有空格:DB_HOST=127.0.0.1✅,DB_HOST = 127.0.0.1❌(会被忽略) - 值含空格或特殊字符必须加引号:
APP_NAME="My App",否则截断或报错
env() 函数返回 null?变量名大小写和前缀要对上
ThinkPHP 的 env() 是对 getenv() 的封装,但默认只读取以 APP_、DB_、CACHE_ 等白名单前缀开头的变量(取决于 think\Env 的 $prefix 配置),其余会被过滤。
- 想读
API_TIMEOUT=3000,得写成env('API_TIMEOUT'),不是env('api_timeout')—— 它区分大小写 - 如果变量不在默认前缀列表里(比如自定义的
LOG_LEVEL),需在think\Env::load()后手动追加允许前缀:think\Env::setPrefix(['APP_', 'DB_', 'LOG_']); - CLI 模式下,系统环境变量优先级高于
.env;若已用export LOG_LEVEL=debug,env('LOG_LEVEL')返回的是系统值,不是.env里的
配置文件里用 {env:xxx} 占位符不生效?注意解析范围
ThinkPHP 支持在 config/database.php 等数组配置中用 {env:DB_HOST} 自动替换,但这仅在配置加载阶段由 think\Config 解析,且只支持一层嵌套(不能写 {env:DB_PORT + 1})。
- 占位符必须严格按
{env:KEY_NAME}格式,冒号后无空格,大括号不可省略 - 若
DB_HOST在.env中为空或未定义,该占位符不会被替换,而是原样保留字符串 —— 导致数据库连接失败,错误信息类似SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed - 配置缓存开启后(
php think optimize:config),.env变更不会实时反映,必须清缓存再试
Swoole 或多进程下 .env 变量“有时有效有时无效”?进程隔离是关键
Swoole Worker 进程启动后不再重新加载 .env,主进程读到的变量也不会自动同步到子进程。如果在 Worker 内部动态修改 $_ENV,其他 Worker 完全感知不到。
立即学习“PHP免费学习笔记(深入)”;
- 所有环境变量应在 Swoole
WorkerStart事件之前、主进程内完成加载,推荐在server.php入口处显式调用think\Env::load() - 避免在
onReceive或控制器中反复调用env()获取高频变量(如API_TOKEN),应提前读取并缓存到静态属性或容器中 - 使用
putenv()动态设置的变量,只对当前进程有效,重启 Worker 后丢失 —— 不适合做运行时开关
最常被忽略的是:ThinkPHP 的 env() 不是全局状态同步器,它只是某次加载快照的只读视图。任何依赖“运行时热更新环境变量”的设计,在长生命周期服务里都得自己加监听或重载逻辑。



















