composer install 严格按 composer.lock 安装精确版本,适用于部署;composer update 重算依赖并更新 lock,需谨慎使用以防不兼容。

依赖发生变化后,Composer 的管理逻辑完全取决于你用的是 composer install 还是 composer update —— 二者行为截然不同,误用是线上故障最常见源头。
composer install 只认 composer.lock,不看 composer.json 的版本约束
只要 composer.lock 存在,composer install 就会严格按里面记录的每个包的精确版本(包括子依赖)去安装,哪怕 composer.json 里写的是 "monolog/monolog": "^2.0",lock 文件里锁的是 2.2.7,它就只装 2.2.7。
- 适用场景:新拉项目、CI/CD 构建、生产部署 —— 目标是环境一致
- 风险点:如果你改了
composer.json但忘了运行composer update生成新 lock,后续install仍用旧版本,你的“新增依赖”或“版本升级”根本不会生效 - 验证方式:执行
composer install --dry-run,看输出是否真有你要装的包
composer update 会重新解析整个依赖图,可能引入不兼容变更
composer update 忽略 composer.lock,根据 composer.json 中的约束重新计算所有包的最新兼容版本,并生成新的 lock 文件。这不是“升级某个包”,而是整棵树重算。
- 典型错误:上线前在生产机上手抖敲了
composer update,结果guzzlehttp/guzzle从7.4.5升到7.8.1,而某中间件依赖其废弃方法,直接报Call to undefined method - 安全做法:只更新明确需要的包,例如
composer update spatie/laravel-permission --with-dependencies,避免牵连无关包 - 加
--dry-run是必选项:先看它打算动哪些包、升到什么版本,再决定是否执行
修改 composer.json 后必须显式触发 lock 更新
手动编辑 composer.json(比如加了个 "require-dev": {"phpunit/phpunit": "^10.5"})不会自动生效。Composer 不监听文件变化。
- 必须运行
composer update phpunit/phpunit或composer update --lock(仅更新 lock,不重装包)才能把新声明写入 lock - 如果只想让 lock 文件反映当前已安装状态(比如你手工删了 vendor 又重装过某些包),用
composer update --lock比install更轻量 - Git 提交时,
composer.json和composer.lock必须同时提交,否则队友install会失败或装错版本
最关键的细节常被忽略:Composer 从不“记忆”你上次 update 用了什么参数,也不保存“意图”。它只忠于当前 composer.json 的声明和 composer.lock 的快照。任何脱离这两者的操作(比如直接删 vendor 再 install)都可能让 lock 和实际安装不一致 —— 这类不一致很难被自动发现,却会在部署时突然爆发。


















