缓存能起效的前提是composer.lock必须提交到仓库且PHP minor版本固定;否则hashFiles('**/composer.lock')返回空哈希导致key失效,PHP patch升级或platform配置不一致也会破坏缓存复用。

缓存能起效的前提是:composer.lock 文件必须提交到仓库,且 PHP minor 版本固定,否则缓存几乎永远不命中。
为什么 composer install 总是重下载,缓存形同虚设?
常见现象是 GitHub Actions 日志里反复出现 Cache not found for input keys,但构建时间没变短。根本原因不是缓存配置写错了,而是缓存 key 实际上每次都在变——哪怕你只改了一行代码,只要 composer.lock 文件没被 git 提交,hashFiles('**/composer.lock') 就返回空哈希,所有缓存 key 都变成一样的字符串,导致“看似恢复成功、实则没内容”。
-
composer.lock必须在 git 中存在且非空;CI 拉取的是干净 clone,不会生成锁文件 - PHP patch 版本升级(如
8.2.10→8.2.12)会破坏缓存复用,因为 Composer 内部缓存键隐式包含 PHP 版本信息 - 如果
composer.json里有"config": { "platform": { "php": "8.1" } },但 workflow 里用了php-version: '8.2',Composer 会降级解析依赖树,导致缓存失效
缓存路径和 key 的正确组合
缓存目标不是 vendor/,而是 Composer 自己的包缓存目录 ~/.composer/cache。这个目录存放的是已下载的 tarball 和解压后的内容,才是可复用的核心资产。
-
path必须设为~/.composer/cache,不能写成vendor/或~/.cache/composer -
key应该包含三要素:${{ runner.os }}+php-${{ matrix.php-version }}+${{ hashFiles('**/composer.lock') }};单独用hashFiles('composer.lock')不够,因为多环境时 OS 差异也会导致缓存不兼容 -
restore-keys可省略,或只保留${{ runner.os }}-php-${{ matrix.php-version }}-作为兜底,避免跨 minor 版本误命中
composer install 命令必须加这三项参数
光有缓存还不够,composer install 必须明确告诉 Composer “别猜,直接用缓存”。否则它可能跳过缓存、回退到源码安装,甚至弹出交互提示中断 CI。
立即学习“PHP免费学习笔记(深入)”;
-
--no-interaction:禁止任何用户输入,CI 环境下必须加 -
--prefer-dist:强制使用压缩包而非 Git clone,才能命中~/.composer/cache中的 tarball -
--optimize-autoloader:生成 classmap,减少运行时文件查找,对大型项目性能提升明显(尤其 Laravel)
本地开发与 CI 环境的一致性检查点
缓存失效常源于本地和 CI 的隐式差异,这些细节容易被忽略但直接影响缓存复用率:
- 确认
composer.json中config.platform.php与 workflow 里php-version完全一致(比如都写'8.2',不能一个写'8'一个写'8.2.0') - 检查是否启用了
COMPOSER_CACHE_DIR环境变量,CI 中不该覆盖默认值~/.composer/cache - 私有包场景下,
github-oauth配置必须在composer install前注入,否则 Composer 会因鉴权失败放弃缓存,转而尝试重新下载
最常被跳过的其实是 composer.lock 是否真实存在于仓库中——CI 不会帮你生成它,也不会报错提醒你漏传,只会安静地每次都重装全部依赖。



















