Symfony 5 环境变量分三层:shell 解析的 .env、编译期 %env()% 表达式、运行时 $_SERVER;APP_ENV 是唯一可信环境开关,决定配置加载与行为,部署前须清缓存,.env 需严格遵循 Shell 规则加引号,敏感值必须通过 %env(resolve:VAR)% 引入,翻译 debug 需显式在 dev 配置中启用。

环境变量在 Symfony 5 中不是“配完就能用”的字符串,而是分三层参与容器构建:启动时由 shell 解析的 .env 值、编译期注入容器的 %env()% 表达式、以及运行时才读取的纯环境变量(如 $_SERVER)。错把它们混用,会导致缓存不生效、参数为空、甚至部署失败。
APP_ENV 是唯一可信的环境开关
它决定整个配置加载链路,不是文件名后缀也不是手动切换路径。Symfony 只认这个值:
-
APP_ENV=dev→ 加载config/packages/dev.yaml和config/services_dev.yaml,启用调试工具栏、禁用缓存 -
APP_ENV=prod→ 加载config/packages/prod.yaml和config/services_prod.yaml,强制缓存、隐藏错误 -
APP_ENV=test→ 仅用于 PHPUnit,config/packages/test.yaml不会自动加载,需显式导入
别写 config_dev.yml 这类文件——Symfony 不扫描文件名后缀。部署前必须清缓存:php bin/console cache:clear --env=prod,否则旧环境配置仍可能残留。
.env 文件要按 Shell 规则写,不是键值对文本
.env 本质是 Bash 脚本,由系统 shell 逐行执行。引号不是可选装饰,而是防止解析错误的必要手段:
- ✅ 必须加引号:含空格(
APP_NAME="My Awesome App")、#(ENV_LABEL="prod #2024")、$(VERSION="v$(git rev-parse --short HEAD)")、>、(、|等 Shell 元字符 - ❌ 不加引号但侥幸成功:纯字母数字(
DB_PASSWORD=secret123) - ⚠️ 危险不加引号:如
DB_URL=mysql://root:pass@db:3306/app—— shell 会尝试执行pass@db:3306/app命令
敏感值(如数据库密码)必须进 .env,再通过 %env(resolve:DATABASE_URL)% 引入配置,不能硬编码在 YAML 里。
参数要分层放,不能全塞进 parameters.yaml
config/parameters.yaml 是全局唯一无条件加载的参数文件,适合放不变的基础值(app.name, app.version),但它不支持被覆盖。环境差异参数必须收口到 services_{env}.yaml:
-
config/services_dev.yaml中定义:database_url: 'sqlite:///%kernel.project_dir%/var/data.db' -
config/services_prod.yaml中定义:database_url: '%env(resolve:DATABASE_URL)%'
这样既避免额外文件管理成本,又确保参数只在对应环境生效。若误把 database_url 写进全局 parameters.yaml,生产环境就拿不到 .env 里的真实值,而是一直用死值。
翻译 debug 开关不会随 APP_ENV=dev 自动开
很多人以为开发环境翻译提示会自动出现,其实不会。组件的 debug 行为必须显式开启,且只能放在对应环境配置中:
在 config/packages/dev.yaml 里加:
framework:
translator:
enabled: true
fallback: en
debug: true
paths:
- '%kernel.project_dir%/translations'如果写进全局 config/packages/translation.yaml,生产环境也会输出未翻译键,暴露内部逻辑结构——这是线上安全风险。
最易忽略的点是:所有 %env()% 引用必须在容器编译期存在,.env 缺失或格式错误会导致 cache:warmup 失败;而 APP_ENV 值一旦设错,后续所有环境专属配置都白配。


















