应该每次运行 composer install,但必须加 --no-dev 和 --prefer-dist,并启用 --optimize-autoloader;需清理 vendor 目录以应对 path 仓库;推荐缓存 ~/.composer/cache 和 vendor/composer 而非整个 vendor;应删除 platform 配置或动态设置;用 composer update --dry-run 验证 lock 文件是否过期;ci 中需启用 opcache.enable_cli=1。

CI 中该不该每次运行 composer install?
应该,但必须加 --no-dev 和 --prefer-dist。CI 环境不需要 phpunit、phpcs 这类开发依赖,不加 --no-dev 会导致安装失败(比如某些 dev-only 扩展在 CI 容器里根本不存在),或拖慢构建速度。而 --prefer-dist 强制走压缩包而非 Git 克隆,避免因网络抖动或 GitHub 限流导致超时。
- CI 脚本中务必写成:
composer install --no-dev --prefer-dist --optimize-autoloader -
--optimize-autoloader生成静态映射,避免 runtime 类名解析开销,对 PHP 7.4+ 尤其明显 - 如果项目用了
path类型仓库(比如本地 monorepo 链接),CI 必须提前rm -rf vendor/,否则composer install会跳过更新
缓存 vendor 目录真的能提速吗?
能,但只在缓存命中时有效;一旦 composer.lock 变更,旧缓存就彻底失效。GitHub Actions、GitLab CI 都支持路径级缓存,但别缓存整个 vendor——它包含绝对路径和平台相关二进制(如 php-cs-fixer 的 phar),跨 runner 复用可能引发权限或执行失败。
- 推荐缓存
~/.composer/cache(Composer 自身下载缓存)和vendor/composer(autoloader 生成中间文件) - GitLab CI 示例:
cache: key: "$CI_COMMIT_REF_SLUG-composer-cache" paths: ["~/.composer/cache", "vendor/composer"] - 注意:若使用
composer update(比如 nightly 构建),必须禁用缓存,否则lock文件更新了但 vendor 没重装,测试跑的是旧代码
composer install 在不同 PHP 版本下行为不一致?
是的,尤其当 composer.json 里写了 "platform": {"php": "8.1"}。CI 如果用 PHP 8.2 运行,但 platform 锁死为 8.1,Composer 会按 8.1 的扩展可用性去解析依赖,可能导致选错版本(比如跳过本可装的 ext-redis 8.2+ 特性版),甚至安装失败。
- CI 中应删掉
platform配置,让 Composer 按真实环境决策 - 如需兼容多 PHP 版本,改用
config.platform.php动态设置:composer config platform.php $(php -v | head -1 | cut -d' ' -f2 | cut -d. -f1,2) - PHP 8.0+ 用户特别注意:
ext-json已内置,但某些旧包仍声明"ext-json": "*",CI 报错时先检查是否误判扩展缺失
流水线里怎么验证 composer.lock 是否过期?
用 composer update --dry-run 检查差异,而不是靠人工比对。它不改任何文件,只输出“哪些包会升级”,适合放进 CI 做门禁:若有输出就 fail,强制开发者先 commit lock 再推。
- 命令示例:
composer update --dry-run --no-dev 2>&1 | grep -q "would be updated" && echo "LOCK OUTDATED" && exit 1 || exit 0 - 注意:
--dry-run在 Composer 2.2+ 才稳定,低版本建议用composer show --outdated --direct替代 - 如果项目允许部分包浮动(如
"monolog/monolog": "^3.0"),这个检查会频繁失败,得配合--with-dependencies或白名单机制
最常被忽略的一点:CI 中 composer install 成功不代表 autoloader 就能用。某些扩展(如 opcache)在 CLI 模式下默认关闭,导致 class not found 错误只在 runtime 出现——得在 CI 的 PHP 配置里显式启用 opcache.enable_cli=1。










