composer prohibits 用于反向查找阻止目标版本安装的包,如运行 composer prohibits symfony/console:^6.0 会列出所有声明不兼容该版本的依赖及其约束。

composer prohibits 是查“谁锁死了旧版本”
它不回答“为什么我装不上新版本”,而是告诉你:当前项目里,哪个包在强制要求某个旧版本,从而把你想要的升级挡在外面。比如你想升 symfony/console 到 ^6.0,但失败了,运行 composer prohibits symfony/console:^6.0 就会列出所有明确声明了 "symfony/console": " 或 <code>"symfony/console": "^5.4" 的上游包。
- 输出中带
requires的行才是真实约束源;replaces或provides行可忽略 - 如果某包出现在多行,说明它被多个路径间接依赖,冲突权重更高
- 若结果为空,不代表没冲突——可能是你写的约束太松(比如只写了
^5.0),根本没触发排斥逻辑
prohibits 和 why-not 的关键区别在哪
composer why-not 是“我想装 X,但谁不让?”;composer prohibits 是“X 被锁在 Y 版本,谁干的?”。前者从目标版本倒推阻塞点,后者从锁定版本正向查源头。实际排查时,这两个命令得配合着用:
- 先用
composer why-not vendor/package:desired-version确认失败路径 - 再用
composer prohibits vendor/package:locked-version找出谁在死守这个旧版 - 如果
why-not输出里反复出现your-project-name,说明是你自己composer.json的require或conflict字段写死了互斥约束
常见误用和坑点
很多人跑 composer prohibits package-name 不加版本号,结果什么也不输出——因为命令必须指定版本才能工作。它不是查“有没有依赖”,而是查“谁在排斥这个具体版本”。
- 必须带完整版本标识,例如
composer prohibits monolog/monolog:^2.0,不能只写monolog/monolog - 如果报
[InvalidArgumentException] Package not found,说明该包当前未被任何已安装或声明的依赖引入,它压根不在你的依赖图里 - 对私有包或 dev 分支,要确保
repositories已配置且能访问,否则命令会跳过它们,导致漏查 - 别指望它识别 PHP 版本或扩展限制——那是
composer update --dry-run -v末尾日志的事
结合 show --tree 验证锁定是否可松动
composer prohibits 告诉你“谁锁了”,但不告诉你“能不能松”。这时候要看 composer show --tree vendor/package 输出末尾的 (locked to X.Y.Z) 标记。这个锁定来自 composer.lock,不是硬编码在 composer.json 里。
- 如果某行写着
locked to 5.4.23,删掉composer.lock再跑composer update vendor/package,才可能绕过这个锁定 - 如果同一包在树中多次出现、版本不一致,说明存在隐式冲突,
prohibits可能只显示其中一条路径,得靠show --tree | grep全局扫 - 注意
--tree展开的是当前 lock 文件的真实状态,不是理想状态——它反映的是“已经发生的妥协”,不是“理论上能怎么选”
why-not 里、也没被 prohibits 抓到,但 show --tree 显示版本明显低于预期的情况。这时候得怀疑平台配置(PHP 版本、ext-json)、镜像缓存,或者某个包的 conflict 字段藏得太深。


















