symfony加载.env文件顺序为.env→.env.local→.env.$app_env→.env.$app_env.local,前提是$_server['app_env']已预设;生产环境须用dotenv:dump编译为.env.local.php,禁用实时解析。

怎么确认当前 Symfony 正在加载哪些 .env 文件
直接看 Dotenv::loadEnv() 的行为逻辑,而不是猜文件名或查文档——它只按固定顺序尝试加载,且每一步都依赖 APP_ENV 是否已设好。最可靠的方式是加一行调试输出,在 public/index.php 或 bin/console 开头插入:
echo "APP_ENV = " . ($_SERVER['APP_ENV'] ?? 'not set') . "\n";
然后运行 php bin/console debug:container --env=prod,观察是否报错“环境变量未定义”。如果报错,说明 .env.prod.local 根本没被读到,大概率是 APP_ENV 没提前设置。
加载顺序不是“自动扫描”,而是条件拼接
loadEnv() 内部会按以下顺序尝试加载(路径基于项目根目录):
-
.env—— 总是加载,不管APP_ENV是什么 -
.env.local—— 总是加载,覆盖.env -
.env.$APP_ENV—— 仅当$_SERVER['APP_ENV']存在且非空时才拼接并尝试加载 -
.env.$APP_ENV.local—— 同样依赖APP_ENV已设,且优先级最高
注意:$APP_ENV 必须是 PHP 运行时可见的环境变量,不能靠 .env 里自己定义的 APP_ENV=prod 来触发后续加载——那行本身会被读,但不会用于决定“要不要加载 .env.prod”。
为什么 .env.prod.local 总是不生效
常见原因就三个:
- Web 服务器没设
SetEnv APP_ENV prod(Apache)或fastcgi_param APP_ENV prod(Nginx),导致 PHP 进程启动时$_SERVER['APP_ENV']为空 -
.env.prod.local文件语法错误(比如漏了引号、用了中文冒号),Dotenv会静默跳过,不报错也不警告 - 该文件被
.gitignore忽略了,部署时根本没传上去
验证方法:在 public/index.php 中加 var_dump(file_exists(__DIR__.'/../.env.prod.local'));,真·看文件是否存在,别信 IDE 的文件树。
生产环境必须用 dotenv:dump 编译,不能依赖 loadEnv()
开发时你可以靠 loadEnv() 动态读多个 .env* 文件,但生产环境禁用此机制。原因有二:
- 每次请求都解析 .env 文件,性能损耗明显(尤其
file_get_contents()+ 正则匹配) - PHP OPcache 不缓存
Dotenv解析结果,变量展开全靠 runtime,容易因环境变量未更新而卡住旧值
正确做法是部署时执行:
php bin/console dotenv:dump --format=php --env=prod
这会生成 .env.local.php,里面是纯 PHP 数组,由内核直接 require,不走 Dotenv。此后 loadEnv() 就不再触发,.env.prod.local 也彻底失效——这点很容易被忽略,以为改了它就能立刻生效。











