composer install不按composer.json升级包,因为它只读取composer.lock文件来确定安装的精确版本;修改composer.json后必须运行composer update(或composer update --lock)更新lock文件,再执行install才能生效。

composer install 为什么没按 composer.json 升级包?
因为它根本不会看 composer.json —— composer install 只读 composer.lock,装什么、装哪个版本,全由 lock 文件决定。你改了 composer.json 里的版本号,不更新 lock,install 就永远装旧的。
常见现象:
- 改完
"guzzlehttp/guzzle": "7.5.0"后跑composer install,vendor 里还是 7.9.2 - CI 构建结果和本地不一致,因为别人提交的 lock 文件没同步你的修改
正确流程是:改 composer.json → 运行 composer update guzzlehttp/guzzle(或 composer update --lock)→ 再 composer install 生效。不走这步,所有版本修改都只是“纸上谈兵”。
composer update --lock 到底做了什么?
它不装新包、不删旧包、不改任何依赖版本,只做一件事:用当前 composer.json + 当前 vendor/ 目录内容,重写一份结构合规、字段完整的新 composer.lock。适用于 lock 文件损坏、格式过时、或 Composer 版本升级后兼容性报错(如 “lock file is not compatible with this version of Composer”)。
关键点:
- 不会触发依赖求解,所以不会解决冲突,也不会降级/升级任何包
- 若
vendor/缺文件或版本错乱,它会照错生成 lock,导致后续install失败 - Git 合并后手动修过 lock 文件?必须先
composer validate,再composer update --lock修复结构
想只升一个包,又怕连带升级一堆子依赖?
默认 composer update vendor/package 会自动拉齐其直系依赖(比如升 monolog/monolog,psr/log 也会跟着升),但不会动无关包。这是合理行为,不是 bug。
如果你明确要锁死子依赖:
- Composer 2.5+ 支持
--no-update-with-dependencies:只升目标包,子依赖保持原样(可能不兼容) - 更稳妥的做法是先查清依赖链:
composer depends vendor/package,再针对性加约束 - 别用
composer require vendor/package:^x.y --no-update,它只改 json,不更新 lock,冲突照旧
注意:加了 --no-update-with-dependencies 后,如果目标包新版实际要求更高版 psr/http-client,运行时大概率报 Class not found 或 Method not exists —— 这不是 Composer 没做对,是你绕过了它本该做的兼容检查。
为什么删了 composer.lock 再 composer install 会失败?
因为 composer install 的设计前提就是 lock 文件存在。它不是“安装工具”,而是“还原工具”。删了 lock 却还跑 install,就像让快递员按一张被撕掉的运单送货——直接报错 Lock file does not contain required package 或拒绝执行。
真正重算依赖的命令只有 composer update(无参数)。它会:
- 忽略旧 lock
- 严格按
composer.json的require和平台配置(如"php": "^8.1")重新求解 - 生成全新 lock,并装对应包
所以“删 lock + install”是无效组合;“删 lock + update”才是重置依赖的正解。生产环境务必确保 composer.lock 已提交且未被 .gitignore,否则每次构建都可能装出不同结果。











