composer install 在 ci 中失败主因是缺失或不匹配 composer.lock 文件,且 ci 环境常缺少 php 扩展、版本不兼容;应确保 lock 文件已提交、禁用 composer update、校验 php 版本与扩展、分环境配置 platform 与 --no-dev、启用合理缓存与 classmap 权威模式。

composer install 为什么在 CI 里总失败
因为默认行为依赖 composer.lock 文件存在且版本匹配,而很多 CI 环境从干净镜像启动,没缓存、没 lock 文件、甚至 PHP 扩展不全。
- 确保 Git 仓库中已提交
composer.lock——CI 不会帮你生成它,composer install没 lock 就直接报错 - CI 脚本里别用
composer update,它会改 lock、触发依赖重解析,破坏可重现性;只用composer install --no-interaction --no-progress --optimize-autoloader --no-dev - 检查 CI 运行的 PHP 版本是否和
composer.json中"php"字段兼容,比如项目要求"^8.1",但 CI 用的是 8.0,composer install会静默跳过某些包或报错 - 有些扩展(如
ext-zip、ext-pdo)在 Alpine 镜像里默认不装,得在 CI 步骤里显式apk add php81-zip类似操作
如何让 composer 自动适配不同环境(dev/test/prod)
靠 COMPOSER_ENV + config.platform + require-dev 分层控制,不是靠写多个 composer.json。
- 生产环境 CI 必须加
--no-dev,否则可能装上phpunit或symfony/debug-bundle这类非运行时依赖,带来安全与体积风险 - 用
config.platform.php锁定目标环境 PHP 版本,防止本地开发是 8.2,CI 是 8.1 却因未设 platform 导致 autoloader 生成异常 -
require-dev里的包不会进生产 autoload,但如果你在代码里写了class_exists('PHPUnit\Framework\TestCase')这种运行时判断,CI 里没装 dev 包就会 fatal error——得用class_exists()+extension_loaded()双检,或改用function_exists()
vendor 目录该不该提交到 Git
不该。但很多人误以为“CI 拉代码慢”就去提交 vendor,结果引入权限、路径、符号链接等一堆不可控问题。
- 提交
vendor会导致 diff 巨大、合并冲突频繁、Git 存储膨胀,且无法验证composer.lock是否真正生效 - CI 慢的主因通常是没做 vendor 缓存——GitHub Actions 可用
actions/cache@v4缓存~/.composer/cache和vendor/;GitLab CI 可用cache:关键字按路径缓存 - 若真遇到某些私有包因认证失败导致 install 卡住,问题不在 vendor 提交与否,而在 CI 的
auth.json配置方式:推荐用composer config http-basic.repo.example.com $USERNAME $TOKEN动态注入,而非硬编码文件
composer dump-autoload --optimize 在 CI 里要不要加
要,但只在生产构建阶段加,且必须配合 --classmap-authoritative 才真正有效。
-
composer dump-autoload --optimize本身只是把 PSR-4 映射转成 classmap,提速有限;真正起效的是--classmap-authoritative,它会让 autoloader 完全跳过文件系统扫描 - CI 构建后如果还要跑测试(比如 PHPUnit),别加
--classmap-authoritative,否则新增测试类不 reload,测试会漏跑 - 这个命令对 symlink 项目(如 Docker volume 挂载的 vendor)可能失效,因为 classmap 写死的是构建时的绝对路径;此时应改用
--apcu-autoloader(需 APCu 扩展)或保持默认 autoload 行为
最常被忽略的一点:所有这些优化都建立在 composer.lock 被严格维护的基础上。一旦有人本地手改了 composer.json 又忘了 composer update 提交新 lock,CI 就会悄悄用旧依赖跑,出问题也难定位。










