composer prohibits 是定位依赖冲突的唯一命令,用于检查指定包(含版本)与现有 composer.json 中声明的依赖(require、require-dev、conflict)的冲突,不扫描 vendor;必须显式指定版本约束,否则默认查不存在的 dev-main。

Composer 不会直接告诉你“谁阻止了升级”,但 composer prohibits 是唯一能定位具体冲突来源的命令。
prohibits 命令的基本用法和常见误用
它不是用来查“当前已安装的包为什么不能升级”,而是查“如果我想装/升级某个包(含版本),哪些现有依赖会与之冲突”。很多人运行 composer prohibits monolog/monolog:^3.0 却得到空结果,是因为没指定版本约束——不带版本号时默认查 dev-main,而该分支很可能根本不存在或未被 require。
- 必须显式带上版本约束,例如
^2.10、>=3.0、dev-main - 目标包名可以是尚未 require 的,也可以是已安装但想升级的
- 它只检查
composer.json中声明的依赖(包括require、require-dev、conflict),不扫描已安装的 vendor 文件
为什么有时 prohibit 结果看起来“不合理”?
常见原因是间接依赖链过长,或者某包在 conflict 字段里写了模糊规则。比如 symfony/console 在其 composer.json 中声明 "conflict": {"symfony/event-dispatcher": ",而你的项目里 symfony/event-dispatcher:5.3 是由另一个包(如 doctrine/doctrine-bundle)拉进来的——prohibits 会把最终源头显示为 doctrine/doctrine-bundle,而不是 symfony/console 自身。
- 输出中每一行代表一个“不可绕过的禁止路径”,从上到下是依赖传递顺序
- 最末尾的包(最后一行)才是真正的冲突发起者,中间的是传递中介
- 若看到
your-project-name出现在某行,说明你composer.json里直接写了冲突版本
实战:查清 laravel/framework:^10.0 升级失败原因
假设执行 composer update laravel/framework --with-all-dependencies 失败,提示 “Your requirements could not be resolved”,这时应立刻用 prohibits 锁定瓶颈:
composer prohibits laravel/framework:^10.0
典型输出可能如下:
laravel/framework 10.0 -> symfony/console ^6.2 -> symfony/console[6.2.0] conflicts with symfony/console[5.4.21] └─ your-project-name requires symfony/console ^5.4
这说明问题不在 Laravel 本身,而在你项目顶层强制锁死了 symfony/console 的旧主版本。解决方向就很明确:要么删掉 "symfony/console": "^5.4" 这行,要么先升级它再试 Laravel。
- 如果输出很长,优先看第一组完整路径(即第一个“->”链),它通常是最短、最直接的冲突路径
- 加
--format=json可用于脚本解析,但人工阅读建议省略该参数 - 配合
composer show -t可交叉验证依赖树中各包的实际解析版本
容易被忽略的细节:prohibits 不处理平台配置和插件逻辑
它只做纯语义版本约束推理,对以下情况无感知:
-
config.platform.php或platform-check导致的跳过安装 - 第三方插件(如
hirak/prestissimo已废弃,或composer-unused)修改了依赖行为 -
replace或provide字段引发的虚拟包替换关系(这些需结合composer show --tree手动推演)
真正卡住升级的,往往就藏在某一行不起眼的 conflict 声明,或某个二级依赖的 require 约束里——prohibits 能把它揪出来,但不会自动帮你改。










