根本原因是每次 job 启动时 ~/.composer/cache 被清空,导致 ZIP 包重复下载解压校验;需用 actions/cache@v4 精准缓存 ~/.composer/cache/files,配合镜像源、prefer-dist、合理并发及禁用 dev 选项等优化。

为什么 GitHub Actions 里 composer install 还是慢
根本原因不是网络差,而是每次 job 启动时 ~/.composer/cache 目录被清空,导致所有 ZIP 包重下、解压、校验。即使 lock 文件没变,缓存也完全失效——这不是 Composer 没缓存,是你没让它用上。
cache action 必须放在 composer install 前且路径精准
actions/cache@v4 必须紧挨着 composer install 步骤,中间不能插入其他修改缓存目录的操作(比如 composer config --global cache-dir)。路径必须精确到 ~/.composer/cache/files,只写 ~/.composer/cache 会命中失败。
- key 推荐用
${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}:lock 文件一变,缓存自动失效,避免旧包污染 - 不要用
COMPOSER_CACHE_DIR改全局路径,CI 容器生命周期短,改了也白改;靠环境变量更可靠 - 如果项目用了私有 Git 仓库(
git@协议),确保 token 不硬编码在命令行,否则可能触发 rate limit 或泄露
--prefer-dist 和镜像源必须同时生效
只配 prefer-dist 不等于提速。如果镜像未生效,Composer 会静默 fallback 到 https://api.github.com/ 克隆 source,速度反而更差。验证方式:运行 composer config -g repo.packagist,输出必须是完整 JSON,且含 "url": "https://mirrors.aliyun.com/composer/"(末尾斜杠不能少)。
- 常见失效点:
repos.packagist(少了个o)、项目级composer.json里写了"prefer-source": true(覆盖全局)、镜像地址已停更(如packagist.phpcomposer.com) - Linux/macOS 可设
parallel-downloads=10,Windows 建议6;设太高会触发临时文件竞争,报file_put_contents(/tmp/): failed to open stream -
--no-dev --optimize-autoloader --no-interaction --no-progress这组参数要一起用,各自砍掉解析、IO、交互、进度条等确定性耗时环节
缓存 vendor/ 是高风险操作
直接缓存整个 vendor/ 目录看似快,但绕过了 Composer 的哈希校验、autoload 生成逻辑和平台兼容性检查。不同 PHP minor 版本(如 8.2.12 → 8.2.15)可能导致 opcache 行为差异,vendor/ 二进制不兼容。
- 安全做法:只缓存
COMPOSER_CACHE_DIR(含 dist 包、metadata、installed.json),每次install仍从缓存重建vendor/ - 若 CI 流程中存在
composer update,务必禁止——生产部署只允许install,否则composer.lock可能被覆盖,历史版本丢失 - 回滚不是靠换 lock 文件再 install,而是靠 Git + 预构建 vendor 包 + ln -sfn 原子切换,这点常被忽略


















