最安全、最推荐的方式是在 services.yaml 中用 %env(resolve:var)% 绑定环境变量,必须加 resolve: 前缀才能真正解析值并支持类型转换,默认值回退及命令展开;手动调用 getenv() 会绕过 symfony 解析机制,导致上线后失效。

在 services.yaml 中用 %env(resolve:VAR)% 绑定参数
读取环境变量最安全、最推荐的方式不是手动调用 getenv(),而是让容器在实例化服务时自动注入。关键点是必须加 resolve: 前缀,否则变量名会被当作文本字面量处理。
-
%env(APP_LOCALE)%→ 传入字符串字面量"APP_LOCALE",不是值 -
%env(resolve:APP_LOCALE)%→ 真正读取 .env 中定义的APP_LOCALE=zh_CN - 类型转换(如
%env(int:API_TIMEOUT_MS)%)也只在resolve:下生效 - 敏感值(如数据库密码)必须走这条路径,避免硬编码或泄露到配置文件中
在 framework.yaml 中绑定 timezone 和 default_locale
仅设 APP_TIMEZONE 或 APP_LOCALE 环境变量不会自动生效——Symfony 不会主动把它们喂给 PHP 或翻译组件。你得显式告诉框架用哪个值。
- 打开
config/packages/framework.yaml - 确保包含这两行(缩进必须严格):
timezone: '%env(resolve:APP_TIMEZONE)%'default_locale: '%env(resolve:APP_LOCALE)%' - 如果缩进错一格,整个配置块会被忽略,且无报错提示
- 改完后要清缓存:
php bin/console cache:clear,否则旧值仍被使用
CLI 命令执行前必须设对 APP_ENV
命令行下读不到 .env.prod.local?大概率是 APP_ENV 根本没生效。Symfony 的环境变量加载完全依赖运行时状态,不是靠文件名“猜”。
- 正确写法:
APP_ENV=prod php bin/console debug:container --parameter=kernel.default_locale - 错误写法:
php bin/console --env=prod ...(该参数已弃用,部分命令不识别) - 验证是否真走 prod:运行
php bin/console debug:dotenv,看输出里有没有.env.prod.local - 线上部署必须预编译:
php bin/console dotenv:dump --format=php --env=prod,生成.env.local.php,不再依赖实时解析
别在 PHP 代码里用 getenv() 读环境变量
直接调用 getenv('DATABASE_URL') 看似简单,但绕过了 Symfony 的变量解析机制,会丢失 resolve: 提供的所有能力:默认值回退(${DB_PORT:-3306})、命令展开($(date +%s))、嵌套引用(${DB_USER}@${DB_HOST})。
- 开发阶段可能“看起来能用”,上线后因缺少
resolve:解析而连不上数据库 - 生产环境服务器应直接设置系统级环境变量,而不是依赖
.env.*文件 - 若真需动态读取(比如调试),优先用
$container->getParameter('env(DATABASE_URL)'),它走的是同一套解析流程 - 注意:PHP-FPM 默认不透传环境变量,Nginx/Apache 需显式配置
fastcgi_param或SetEnv
resolve: 前缀和 APP_ENV 的运行时设置——这两个点一错,其他全白配。











