composer show 默认不显示 conflict 字段,需加 -s 参数或用 JSON 格式配合 jq 提取;conflict 仅为作者声明的兼容性提示,不参与依赖解析,也不阻止安装成功。

composer show 如何查包的 conflict 字段
直接看 composer show 默认不显示 conflict,它只列 name、version、source 和简略描述。想确认某个包是否声明了冲突依赖,得加 -s(show details)或用 JSON 输出再过滤。
- 查单个包:运行
composer show -s vendor/package-name,向下翻找conflict键值对,有就显示,没写就是空或不存在 - 批量检查?别手动翻,改用
composer show --format=json vendor/package-name | jq '.conflict'(需装jq),返回null表示未定义,否则是对象如{"php": ">=8.3"} -
conflict是包作者在composer.json里写的约束,不是 Composer 自动推导的——它不参与安装时的 solver 计算,只起提示作用
为什么 conflict 不阻止安装成功
很多人看到 conflict 字段报错却仍能 composer install 成功,是因为 Composer 的依赖解析器根本**不强制校验它**。它只在 composer validate 或 composer update --dry-run 时做轻量提示,且默认静默。
- 真正起作用的是
require和require-dev中的版本约束,solver 围绕它们做图遍历 -
conflict只在composer install后、执行composer check-platform-reqs或某些 CI 插件中被读取,属于“事后提醒”而非“事前拦截” - 如果你发现某包写了
"conflict": {"laravel/framework": "10.*"},但项目仍装了 Laravel 10 —— 这不违法,只是作者在说“我测试过不兼容”,你得自己担风险
conflict 和 require 的关键区别在哪
混淆这两者是踩坑主因。require 是“我要用这个”,conflict 是“我明确不支持这个”,但后者没有反向约束力。
-
require写"php": "^8.1"→ 安装器会拒绝 PHP 7.x 环境 -
conflict写"php": "8.3.0"→ 即使当前是 PHP 8.3.0,composer install也照常运行,除非你额外启用校验 - 更隐蔽的坑:
conflict支持通配符(如"monolog/monolog": "),但它不会触发自动降级;而 <code>require写成"monolog/monolog": "^2.10"才会强制拉取满足条件的版本
如何让 conflict 真正生效(避坑实操)
靠包作者写的 conflict 字段本身做不到强制拦截,必须配合外部机制。
- CI 中加一步:
composer validate --strict,它会把缺失conflict或格式错误标为失败(但依然不检查内容逻辑) - 用插件:安装
ergebnis/composer-normalize并配置"conflict": true在extra里,可强制要求所有包声明conflict字段(治标不治本) - 最靠谱的做法:在项目根
composer.json的conflict里主动写死已知不兼容项,例如"conflict": {"ext-gd": ",这时 Composer 会在 <code>install前检查扩展版本(仅限平台包)
真正难的不是找到 conflict 字段,而是判断它背后有没有对应的实际测试覆盖——很多包写了 conflict 却从未跑过对应环境的测试,这种声明等于没写。










