APP_ENV是唯一可信环境开关,决定配置加载与行为;.env文件需严格遵循Shell规则加引号;敏感值必须通过%env(resolve:VAR)%引入,部署前须清缓存。

环境变量不是“写完就能用”,APP_ENV 才是 Symfony 真正认的开关,其他变量(比如 DATABASE_URL)只是参数,不决定加载哪套配置。
APP_ENV 是唯一可信的环境开关
你改了 .env 里的 APP_ENV=dev,Symfony 就加载 config/packages/dev/ 下的配置;改成 prod,它就跳过所有 dev 相关文件,连 services_dev.yaml 都不会碰。这个判断发生在编译期,不是运行时查 $_ENV['APP_ENV']。
-
APP_ENV必须通过系统环境变量或.env文件设置,不能在 PHP 代码里动态改 - 部署前必须执行
php bin/console cache:clear --env=prod,否则缓存里还存着旧环境的配置 -
APP_DEBUG=true不影响环境切换,只控制错误页面和 profiler 是否启用
.env 文件加载顺序与覆盖规则
Symfony 按固定顺序加载 .env 文件:先 .env,再 .env.local,然后是 .env.<code>APP_ENV(如 .env.prod),最后是 .env.<code>APP_ENV.local(如 .env.prod.local)。后面读到的同名变量会覆盖前面的。
-
.env.local不该提交到 Git,里面放本地数据库密码、API key 等敏感值 -
.env.prod可以放在部署流程中生成,但不要硬编码进项目仓库 - 如果
.env里写APP_ENV=dev,而.env.local里写APP_ENV=prod,最终生效的是prod - 引号必须严格匹配 Shell 规则:含空格或特殊字符的值要用单引号或双引号包裹,比如
DATABASE_URL="mysql://user:p@ss!@localhost/db"
环境变量怎么安全地进配置文件
直接在 YAML 里写 %env(DATABASE_URL)% 是错的——它会被当字符串字面量,不解析。必须加 resolve: 前缀,让 Symfony 在编译期展开。
- 正确写法:
url: '%env(resolve:DATABASE_URL)%' - 敏感值(如密钥)推荐走
%env(resolve:VAR)%+secrets:set加密机制,而不是全靠.env -
parameters.yaml里不能直接引用%env()%,它不参与环境变量解析流程;所有环境相关参数都应通过config/packages/*.yaml中的%env()%表达式注入 - 验证是否生效:运行
php bin/console debug:container --env-vars,看变量是否出现在列表里且值正确
为什么本地能跑,生产报 “Database connection failed”
常见原因是 DATABASE_URL 在生产环境没被正确注入,或者 APP_ENV 被误设为 dev 导致加载了 SQLite 配置。
- 检查
php -r "var_dump($_SERVER['APP_ENV'] ?? null);",确认 Web 服务器传入的APP_ENV值 - Nginx 用户容易漏掉
fastcgi_param APP_ENV prod;这行,Apache 用户要确认SetEnv APP_ENV prod已启用 - 清缓存后仍失败?用
php bin/console debug:config doctrine看实际解析出的url是什么,不是看.env文件写了什么 - 容器部署时,别把
.env当成唯一来源——Docker 的environment:或 Kubernetes 的envFrom:优先级更高
最常被忽略的点:环境变量解析只发生在容器编译阶段,一旦缓存生成,改 .env 文件也不会自动生效;每次改完都得清缓存,而且得用对应环境清——php bin/console cache:clear --env=prod,不是 --env=dev。


















