composer install 报 conflict 错误时,应先检查 composer.lock 与 composer.json 是否一致,运行 composer install --dry-run 预览冲突,用 composer why-not 定位阻塞包,避免盲目执行 composer update。

composer install 报 conflict 错误时,先看它锁了什么
Composer 不是凭空报冲突的,它严格按 composer.lock 里记录的版本安装。如果本地 composer.lock 和当前 composer.json 不一致(比如别人提交了新依赖但没更新 lock),或者你手动改过 composer.json 但没跑 composer update,composer install 就会卡在冲突检测阶段,直接失败。
实操建议:
- 先运行
composer install --dry-run,它不装包,只模拟并告诉你哪几个包“想装但装不了” - 对比
composer.json和composer.lock里同名包的版本号,尤其注意require和require-dev是否有新增/删减 - 如果 lock 文件明显旧了(比如 Git 提示它被修改但你没动过),别硬试
install,直接composer update --lock同步 lock
用 composer why-not 定位具体哪个包在拦路
composer why-not 是最接近“检测冲突”的真实命令——它不解决,但说清谁在反对你想要的版本。比如你想升 monolog/monolog 到 ^3.0,但失败了,就跑:
composer why-not monolog/monolog:^3.0
输出会列出所有阻止该版本的依赖项,包括间接依赖(比如 A 依赖 B,B 又锁死了 monolog ^2.0)。
常见错误现象:
- 输出里出现
your-project-name——说明是你自己的composer.json里写了冲突的约束 - 输出里全是第三方包,但没提你自己 ——大概率是某个包的
composer.json在require里写了死版本或窄范围 - 结果为空?那不是冲突,可能是网络问题或 packagist 镜像没同步新版本
composer update 不是万能解药,乱用反而放大冲突
composer update 默认更新所有包,相当于让 Composer 重新解一遍整个依赖图。它可能“解决”当前冲突,但也可能引入新冲突、破坏稳定性,尤其在生产环境或团队协作中。
更可控的做法:
- 只更新目标包:
composer update vendor/package-name(例如composer update guzzlehttp/guzzle) - 加
--with-all-dependencies让它连带更新该包的子依赖,避免半途卡住 - 加
--dry-run先预览变更,确认没有意外升级主版本(比如从 v2 升到 v3) - 别在 CI 或部署脚本里无条件跑
update,install才是上线标准动作
性能影响:全量 update 会触发大量远程元数据请求,耗时远超 install,且容易因临时网络抖动失败。
兼容性陷阱:PHP 版本和平台配置常被忽略
很多“冲突”根本不是包之间的事,而是 Composer 检测到你的 PHP 版本不满足某个包的 php 要求,或扩展缺失(比如某包 require ext-gd,但你环境没开)。这类报错常混在一大段 conflict 输出里,一眼扫过去容易漏。
检查方式:
- 运行
composer config platform.php看是否手动锁定了 PHP 版本(有些项目为兼容旧环境设了"7.4",但实际跑在 PHP 8.2 上) - 执行
php -m确认必需扩展已启用 - 查报错里有没有类似
The requested PHP extension ext-xxx is missing或Your PHP version (8.1.0) does not satisfy that requirement
最容易被忽略的一点:Docker 或 CI 环境里,composer install 和 php -v 看到的 PHP 版本可能不一致——因为 Composer 会读取 platform 配置优先于真实环境,而这个配置常被遗忘在 composer.json 里硬编码着。










