composer show --tree 不检测兼容性冲突,因它仅展示已安装依赖树且信任 lock 文件;真冲突需通过 composer update --dry-run、composer why-not 或 composer prohibits 主动解析约束。

composer show --tree 为什么看不到兼容性冲突?
因为 composer show --tree 只展示当前已安装的依赖树,不校验版本约束是否满足——它假设 lock 文件是合法的。真正检测兼容性,得让 Composer 主动“尝试解析”,而不是读取结果。
常见错误现象:composer install 成功,但 composer update foo/bar 报错 Your requirements could not be resolved,说明局部更新时暴露了隐含冲突。
- 用
composer update --dry-run触发完整依赖解析,但不写入 lock 文件,能提前看到冲突提示 - 加
-vvv可看到详细回溯,比如哪条require规则和哪个包的conflict段撞上了 - 注意:如果项目有
platform配置(如"php": "8.1"),而本地 PHP 版本不同,--dry-run也会报错,这不是包冲突,是环境不匹配
composer why-not 能定位具体不兼容的包
composer why-not 是最直接的诊断命令,它回答“为什么这个包不能装上”,而不是泛泛查兼容性。
使用场景:你想升级 monolog/monolog 到 ^3.0,但失败了,就运行:
composer why-not monolog/monolog:^3.0
输出会列出所有阻止安装的依赖项及其约束,例如:
laravel/framework v10.10.0 requires monolog/monolog ^2.9 -> satisfiable by monolog/monolog[2.9.0, ..., 2.9.2].
- 它只检查当前
composer.json和 lock 中的约束,不模拟全新安装 - 如果某包在 require-dev 里,也要加
--dev才能被纳入分析 - 输出中出现
root行,说明是你自己写的require或conflict直接挡住了
composer prohibits 命令比 why-not 更早发现问题
composer prohibits 不依赖当前 lock 状态,而是纯静态扫描 composer.json 里的所有 require、conflict 和 replace 字段,适合在改依赖前预判。
比如你准备引入 symfony/console:^6.4,先跑:
composer prohibits symfony/console:^6.4
它会立刻告诉你哪些已有依赖明确 conflict 这个版本,或者要求更低版本(如 symfony/event-dispatcher: ^5.4 通常和 console:^6.4 不兼容)。
- 它不下载包元数据,所以快,且不依赖网络或 vendor 是否存在
- 但它看不到间接依赖的约束——比如 A 依赖 B,B 的 composer.json 里写了 conflict,
prohibits不会递归检查 B - 配合
composer show -p查看某包所有已知版本及其 require/conflict 声明,才能补全链条
第三方工具:composer-versions-check 的真实价值在哪
composer-versions-check 是一个轻量 CLI 工具,它不替代 Composer 自身逻辑,而是把 packagist.org 上所有公开版本的 require 和 conflict 提取出来建本地索引,做跨包兼容性推演。
它解决的是 Composer 原生命令做不到的事:比如“当前项目里所有包,有没有任意两个之间存在未声明但实际不兼容的 PHP 版本要求?”
- 安装后运行
composer-versions-check check,会报告类似:Package x requires php >=8.0, but y requires php - 它不修改任何东西,只读取 lock 文件和远程元数据,适合 CI 中做兼容性卡点
- 注意:它依赖 packagist 数据新鲜度,如果某包刚发版还没同步,可能漏报;另外私有仓库需额外配置 API token
复杂点在于,兼容性从来不是单点问题——PHP 版本、扩展启用状态、autoload 规则、甚至 minimum-stability 设置都会改变依赖解析结果。别只盯着版本号对齐,先确认你的 platform 配置和实际运行环境一致。










