CI 中 composer install 慢的根本原因是每次构建都重新下载解压依赖并生成自动加载文件,必须同时缓存 vendor 目录和 COMPOSER_CACHE_DIR,并使用 --no-interaction --prefer-dist --optimize-autoloader 参数。

CI 中 composer install 为什么慢
根本原因是每次构建都重新下载全部依赖包,尤其是 vendor/ 目录重建 + ZIP 包解压 + 自动加载文件生成,叠加网络波动和 Packagist 响应延迟,单次耗时常超 2 分钟。缓存不是“可选优化”,而是 CI 稳定性的刚需。
必须启用的两个缓存层:vendor 和 Composer 自身 cache-dir
只缓存 vendor/ 不够——Composer 在安装前会先从 cache-dir 解包 ZIP、校验哈希、写临时文件;若 cache-dir 每次清空,仍要重复下载和解压。正确做法是同时持久化:
-
vendor/目录(注意:需排除vendor/bin/符号链接和部分生成文件) -
COMPOSER_CACHE_DIR对应路径(默认~/.composer/cache),它存的是已下载的 ZIP 和 dist 包元数据
GitHub Actions 示例配置片段:
steps:
- name: Cache Composer dependencies
uses: actions/cache@v4
with:
path: |
vendor
~/.composer/cache
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}-${{ hashFiles('**/composer.json') }}composer install 必须加 --no-interaction --prefer-dist --optimize-autoloader
这三个参数缺一不可:
-
--no-interaction:避免 CI 环境下因缺少 TTY 导致卡住(尤其某些插件会询问配置) -
--prefer-dist:强制走 ZIP 包安装(比 source 快 3–5 倍),且能命中COMPOSER_CACHE_DIR中的缓存包 -
--optimize-autoloader:生成扁平化autoload_classmap.php,跳过运行时文件扫描,PHP 加载类快 20%+,对测试启动时间敏感的场景明显
漏掉 --prefer-dist 会导致即使有 cache-dir,也绕过 ZIP 缓存走 git clone,彻底失效。
lock 文件变更时缓存失效策略要精准
缓存 key 若只基于 composer.lock 哈希,看似合理,但实际易误判:
- lock 文件里含平台配置(如 PHP 版本、扩展列表),CI 环境升级 PHP 后,旧缓存可能装错扩展兼容版本
- 某些私有仓库 token 或镜像配置变更不会反映在 lock 中,但影响下载行为
推荐 key 组合:${{ runner.os }}-php-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }},显式绑定 PHP 版本,避免跨版本缓存污染。私有源变动则需手动触发 cache 清理或增加配置哈希段。
真正麻烦的是 dev 依赖与 require-dev 的混用——它们出现在 lock 里,但 CI 测试阶段才需要。若缓存包含 dev 包,而 prod 构建误用了该缓存,会引入非预期依赖。建议按环境拆分 cache key,或统一用 --no-dev(生产构建)与 --with-all-dependencies(测试构建)隔离。










