composer install 严格按 composer.lock 安装,确保环境一致;改 composer.json 后需 run update 生成新锁,否则 install 无反应;lock 文件必须提交 git,否则导致依赖不一致。

composer install 是读锁文件装包,不是“重新安装”
很多人以为 composer install 是从 composer.json 重新拉一遍依赖,其实它优先看 composer.lock —— 只要这个文件存在且没被删,它就严格按锁文件里记录的版本、哈希、源地址来安装,连网络请求都可能跳过(如果本地有对应 zip 缓存)。这保证了团队成员和 CI 环境装出来的东西完全一致。
常见错误现象:
• 改了 composer.json 增加一个包,但运行 composer install 没反应 → 因为锁文件没更新,它只装已有记录
• 本地装得好好的,CI 报错说找不到某个类 → 锁文件没提交,或别人改了 composer.json 但没跑 update 生成新锁
- 执行前务必确认
composer.lock已提交到 Git,且和当前composer.json匹配 - CI/CD 流水线应始终用
composer install --no-dev(生产环境)或composer install(测试环境),而不是update - 如果删了
composer.lock再跑install,行为等价于update—— 这是意外,不是设计意图
composer update 是解构依赖树并重算版本,慎用
composer update 的核心动作是:丢掉 composer.lock,根据 composer.json 里的约束(如 "monolog/monolog": "^2.0"),联网查最新满足条件的版本,再递归解析所有子依赖冲突,最后写回新的 composer.lock。它本质是一次“依赖求解”,耗时长、结果不可控,且会改变锁文件。
使用场景有限:
• 你明确要升级某几个包(比如 composer update doctrine/dbal symfony/console)
• 项目刚初始化,还没生成锁文件
• 安全补丁必须落地,且已确认新版兼容
- 永远不要在生产环境或未测分支上直接跑
composer update - 加
--dry-run先看会动哪些包:composer update --dry-run - 升级单个包时,记得带上其子依赖是否联动(例如
composer update phpunit/phpunit --with-dependencies) - PHP 版本升级后,
update可能因平台约束失败,需先检查config.platform.php是否锁定旧版
lock 文件不提交 = 团队依赖不一致的根源
composer.lock 不是临时文件,它是 Composer 保证可重现性的唯一凭证。Git 忽略它,等于放弃语义化版本承诺 —— 每个人跑 install 实际得到的是不同时间点的依赖快照。
典型症状:
• 本地 php artisan tinker 能跑,部署后报 class not found
• 同一 commit,A 同学 install 出 v3.2.1 的包,B 同学出 v3.2.5,行为微异
-
.gitignore里删掉/composer.lock相关行(如有) - 提交前检查:
git status | grep composer.lock,确保它在待提交列表里 - 如果多人同时改了
composer.json,合并后必须立刻composer update生成新锁,并一起提交
为什么有时候 install 会连网?不是说离线也能装?
composer install 理论上可离线,但实际常触发网络请求,原因很具体:
• 锁文件里记录的是 dist 包 URL,而本地缓存缺失(比如清过 ~/.composer/cache)
• 包源配置变了(如从 packagist.org 切到私仓),但锁文件还是旧地址
• 启用了 fxp/composer-asset-plugin 等插件,它们有自己的下载逻辑
- 验证是否真离线可用:
composer install --no-network,报错即说明缺缓存或源不匹配 - 私有仓库环境下,确保
composer config -g repos.packagist composer https://your-private-mirror已配置,且锁文件中 URL 已同步更新 - CI 中建议加
composer install --prefer-dist --no-interaction,避免 fallback 到 source 方式(更慢、更易失败)
锁文件的哈希校验和源地址绑定是硬性约束,任何网络请求失败,都意味着当前环境无法满足锁文件声明的完整性要求——这不是 bug,是设计在喊你检查环境一致性。