composer通过${var_name}占位符在运行时调用getenv()解析环境变量,需提前在shell、ci env块、docker或systemd中显式注入;仅config.http-basic、repositories[].url等明确支持插值的字段生效,.env文件和autoload.php不参与此过程。

composer命令里怎么读取环境变量
Composer 本身不主动加载 .env 或 shell 环境变量来控制行为,但它的很多配置项(比如仓库地址、认证凭据)支持用 ${VAR_NAME} 占位符,运行时由 PHP 的 getenv() 解析。这意味着:你得先让系统或 PHP 进程能读到这些变量。
常见错误是直接在 shell 里 export COMPOSER_AUTH=...,然后跑 composer install —— 大部分情况下它确实能生效;但一旦进到 CI/CD 或容器里,或者用了 sudo、systemd 启动的进程,环境变量就丢了。
- 本地开发:在 shell 配置文件(如
~/.zshrc)里export,再source一下 - CI/CD(GitHub Actions / GitLab CI):必须显式用
env:块注入,不能靠.env文件自动加载 - Docker:用
ENV指令或--env参数传入,docker-compose.yml中的environment:也得写全
composer.json 里哪些字段支持变量替换
只有明确文档标注「支持变量插值」的字段才认 ${FOO},不是所有字段都行。最常被误用的是 config.repos 和 config.github-protocols,它们不支持;而下面这些可以:
-
config.http-basic:用于私仓认证,值可写成{"example.com": {"username": "${GIT_USERNAME}", "password": "${GIT_TOKEN}"}} -
repositories[].url:比如私有 Packagist 地址,写成"${PRIVATE_REPO_URL}" -
config.notify-batch、config.process-timeout等数值型配置,也可以用变量(需确保变量值是数字字符串)
注意:composer.json 里的变量只在运行时展开,不会写回文件;如果变量未定义,Composer 默认忽略该字段(不报错),容易导致静默失败。
为什么 vendor/autoload.php 加载不了 .env 变量
因为 Composer 的自动加载器(vendor/autoload.php)只管类文件映射,它不负责加载环境变量。有人试图在 autoload.files 里加 dotenv 的加载逻辑,这会导致两个问题:
- 项目还没装
vlucas/phpdotenv时,composer install就会失败(循环依赖) - 即使装了,
autoload.files是在 Composer 自身执行完之后才加载的,对composer.json里的变量插值毫无作用
真正起作用的时机,是 Composer 启动时(PHP 进程刚起来那刻)——它调用 getenv(),所以你要么提前用 shell 设置好,要么在 PHP 启动前用 putenv() 注入(比如通过 php.ini 的 auto_prepend_file)。
CI 环境下最稳的变量传递方式
别信“只要把 .env 放进项目根目录就能用”,CI 默认不执行 dotenv 加载逻辑。最可靠的做法是:把敏感变量从 CI 配置中直接注入为环境变量,并在 composer.json 里用占位符引用。
例如 GitHub Actions:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PRIVATE_REPO_URL: https://token:${{ secrets.PRIVATE_REPO_TOKEN }}@packages.example.com
对应 composer.json 片段:
"repositories": [
{
"type": "composer",
"url": "${PRIVATE_REPO_URL}"
}
]
关键点:变量名必须全大写、不含特殊字符;CI 中 secret 值不能带换行或空格;如果 URL 中含 @ 符号,记得 URL 编码处理,否则 parse_url() 会截断。
复杂点在于,不同 CI 对环境变量的继承规则不一致,有些步骤默认不继承上一步设置的 export,必须统一用顶层 env: 声明。这点容易被忽略,一查日志发现 ${FOO} 居然原样留在 URL 里没替换,就是这个原因。










