CI 中 composer install 慢的根源是未缓存 vendor 和 ~/.composer/cache,且未使用 --prefer-dist 等关键参数;必须同时缓存两路径、key 包含 PHP 版本与 composer.lock hash,并严格匹配 platform.php 版本。

CI 中 composer install 慢,不是网络问题,是没缓存 vendor 和 Composer 自身缓存目录,且参数用错了。
为什么 composer install 在 CI 里总卡住
GitHub Actions 每次都从零开始:下载所有包、解压、生成 autoloader、写 classmap——哪怕只改了一行测试。默认不启用任何缓存,COMPOSER_CACHE_DIR(默认 ~/.composer/cache)和 vendor/ 都被丢弃。更常见的是漏掉 --prefer-dist,导致 Composer 回退到 git clone,彻底绕过 ZIP 缓存。
- 不加
--prefer-dist→ 即使有 cache,也会走源码克隆,速度下降 3–5 倍 - 没缓存
~/.composer/cache→ 每次重下 ZIP 包,重复解压校验 - 缓存 key 没包含
composer.lockhash → lock 文件一变,缓存就失效,但你可能根本没意识到 - 用了
actions/setup-php而非shivammathur/setup-php→ 扩展加载不稳定,间接导致某些包 install 失败后重试,拖慢流程
actions/cache@v4 必须同时缓存两个路径
只缓存 vendor 不够,Composer 下载的 ZIP 包和元数据存在 ~/.composer/cache,不缓它,下次还是得重新 fetch。两者必须一起缓存,且 key 要能区分 PHP 版本和依赖锁定状态。
- path 字段要写成多行,用
|引导:
path: | vendor ~/.composer/cache
${{ runner.os }}-php-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
**/composer.json 做 hash 来源——它常含 dev 依赖变动,导致缓存频繁失效安装命令必须带这四个参数
composer install 在 CI 里不能照搬本地命令。少一个参数,就可能触发交互、加载 dev 依赖、生成冗余文件或跳过优化。
-
--no-interaction:禁止任何 prompt(比如 auth token 询问) -
--prefer-dist:强制用 ZIP 包,跳过 git clone -
--optimize-autoloader:生成扁平 classmap,加速class_exists查找 -
--no-progress:避免 ANSI 控制符污染日志,也略微提速 - 不要加
--no-dev——除非你明确只跑 prod 构建;测试通常需要require-dev里的工具
PHP 版本与 config.platform.php 必须严格一致
CI 报 “Your requirements could not be resolved”,90% 是因为 composer.json 里写了 "config": {"platform": {"php": "8.2.10"}},但 workflow 中只写了 php-version: '8.2'。Composer 会按 platform 声明模拟环境解析依赖,版本号不完全匹配就失败。
- workflow 中用
php-version: '8.2.10'(和 platform 完全一致) - 或者干脆删掉
config.platform.php——现代项目更推荐让 Composer 真实运行环境决定兼容性 - 检查扩展是否启用:如需
ext-gd,在shivammathur/setup-php步骤中加extensions: gd - 加一步验证:
run: composer show --platform | grep php,确认实际解析的平台版本
最易被忽略的是缓存 key 中 PHP 版本的粒度——写 8.2 看似简洁,但 8.2.0 和 8.2.10 的扩展 ABI 可能不同,混用缓存会导致 vendor 里混入不兼容的二进制扩展,后续 php -m 或测试直接 segfault。


















