%env()% 是 symfony 容器编译期解析环境变量的语法,仅在 yaml/php 配置文件中生效,非 php 函数;它读取系统级环境变量(非 .env 文件),支持 default:、int:、json:、base64:、resolve: 等修饰符,且值必须在容器构建前由系统、docker 或运维方式注入。

什么是 %env()%,它和普通参数有什么区别
%env()% 不是 Symfony 的函数,而是容器编译期的环境变量解析语法,只在 YAML/PHP 配置文件(如 config/services.yaml)中生效。它和直接写死的字符串、或引用 %kernel.environment% 这类内建参数完全不同:前者在容器构建时读取系统环境变量,后者是运行时注入的值。
常见错误是把它当成 PHP 函数调用,比如在控制器里写 %env(APP_SECRET)% —— 这会原样输出字符串,根本不会解析。
- 必须出现在配置文件中(
services.yaml、doctrine.yaml等),不能用于 PHP 代码或 Twig 模板 - 环境变量名不区分大小写,但建议全大写(如
APP_ENV),且需在 Symfony 启动前由系统或 Web 服务器设置好 - 若环境变量未设置,默认会报错;可加默认值:
%env(default::FOO)%→ 若FOO未定义,则用空字符串代替
%env() 支持哪些修饰符,什么时候该用 resolve:
修饰符(如 string:、int:、json:、base64:、resolve:)决定如何转换原始环境变量值。最易踩坑的是 resolve: —— 它让 Symfony 再次解析字符串里的占位符,常用于拼接路径或组合参数。
例如,你想把 APP_DATA_DIR 和子目录 cache 拼成完整路径:
parameters:
app.cache_dir: '%env(resolve:APP_DATA_DIR/cache)%'
如果不用 resolve:,%env(APP_DATA_DIR)/cache% 会被当作文本字面量,不会展开 APP_DATA_DIR 的值。
-
int:强制转整数(%env(int:DB_PORT)%),避免字符串比较出错 -
json:解析 JSON 字符串(%env(json:REDIS_OPTIONS)%→{"timeout": 5}) -
base64:解码 Base64 值(适合密钥等二进制内容) -
default:必须放在最前:%env(default::dev)%,不是%env(dev:default)%
为什么 %env() 在 .env 文件里不生效
Symfony 的 .env 文件由 Dotenv 组件加载,它只负责把变量注入到 PHP 的 $_ENV 和 $_SERVER 中,供 %env()% 读取。但 %env() 本身**不读 .env 文件** —— 它只读操作系统级环境变量。
所以你在 .env 里写了 API_KEY=abc123,却在 services.yaml 里用 %env(API_KEY)% 报错,大概率是因为:
- Web 服务器(如 Apache/Nginx)没把
.env变量透传给 PHP 进程(CLI 下通常没问题) - 用了 Docker 但没通过
environment:或env_file:显式挂载变量 - 开发时改了
.env却没重启 Web 服务器或 CLI 进程(变量只在启动时加载一次)
验证方法:在控制器里写 dump($_ENV['API_KEY'] ?? 'not set');,看是否输出 abc123。如果不是,%env() 就不可能读到。
生产环境部署时,%env() 的值从哪来
生产环境严禁依赖 .env 文件。所有 %env() 引用的变量必须由运维通过系统级方式注入:
- Linux systemd service:在
[Service]段加Environment="DATABASE_URL=..." - Docker:用
-e DATABASE_URL=...或environment:字段 - Kubernetes:通过
env:或envFrom:注入 ConfigMap/Secret - Apache:用
SetEnv指令(需启用env模块) - Nginx + PHP-FPM:在
php-fpm.conf的env[DATABASE_URL]配置项里设
关键点:这些变量必须在 PHP 进程启动前就存在。如果你在 public/index.php 开头 putenv('FOO=bar'),%env(FOO)% 仍然读不到 —— 因为容器早已编译完成。











