Symfony环境变量注入需用%env(resolve:VAR)%声明式绑定,否则仅作字符串字面量;命名参数+autowire可省略arguments配置;APP_ENV必须由Web服务器显式设置;生产环境须运行dotenv:dump生成编译文件以避免重复解析开销。

环境变量注入服务不是“读取”而是“声明式绑定”——你不需要在构造函数里调用 getenv(),也不该在服务类里硬编码 $_ENV。Symfony 的容器会在实例化时自动把解析好的值塞进去,前提是配置写对了。
services.yaml 里必须用 %env(resolve:VAR)% 才能生效
直接写 %env(DB_HOST)% 是无效的:它只是字符串字面量,不会触发环境变量解析。只有加上 resolve: 前缀,Symfony 才会真正去读取 .env 或系统环境变量。
-
%env(resolve:DB_HOST)%→ 正确,会读取DB_HOST=localhost -
%env(DB_HOST)%→ 错误,注入的是字面字符串"DB_HOST" - 类型转换(如
int:、bool:)也依赖resolve:,否则不生效 - 如果变量含默认值或嵌套引用(如
${DB_PORT:-3306}),同样只在resolve:下展开
PHP 8+ 构造函数命名参数可省略 YAML 配置
如果你的服务构造函数用了命名参数 + 类型提示,且启用了 autowire: true,那连 arguments: 块都可以省掉。
- 类定义示例:
public function __construct(private string $apiEndpoint, private int $timeout) - 确保
services.yaml中有_defaults: { autowire: true, autoconfigure: true } - 再在
_defaults.bind下统一绑定:$apiEndpoint: '%env(resolve:API_ENDPOINT)%' - 这样所有用到
$apiEndpoint参数名的服务都会自动注入,无需逐个写arguments
生产环境必须提前设好 APP_ENV,否则 .env.prod.local 不加载
很多人发现 .env.prod.local 里的变量没生效,根本原因是 Web 服务器没设置 APP_ENV=prod。Dotenv 加载器不会“猜”环境,它严格按顺序查找:.env → .env.local → .env.$APP_ENV → .env.$APP_ENV.local。
- Apache 配置中加:
SetEnv APP_ENV prod - Nginx 配置中加:
fastcgi_param APP_ENV prod; - CLI 下验证:
echo $APP_ENV,必须输出prod而不是空 -
.env.prod.local必须在.gitignore中,且不能有语法错误(比如漏引号、未闭合的${})
最容易被忽略的一点是:resolve 开销在生产环境不可忽视。每次请求都解析 %env(resolve:...)% 会拖慢响应,所以生产部署前一定要运行 bin/console dotenv:dump,生成 .env.local.php 编译文件。否则,你写的全是“正确但慢”的配置。











