composer why-not用于快速定位包版本安装失败的阻塞源头,通过反向依赖链揭示具体冲突点,如PHP版本不满足、已装包版本锁定或conflict声明等。

composer why-not 能立刻告诉你谁在拦路
报错说装不上某个包,别急着改 composer.json 或删 vendor。先用 composer why-not 直接问 Composer:到底谁不让我装?
它输出的是真实阻塞链,不是推测。比如运行 composer why-not laravel/sanctum:^3.0,可能得到:
myapp/myproject dev-main requires guzzlehttp/guzzle (^6.5) laravel/sanctum ^3.0 requires guzzlehttp/guzzle (^7.2)
这说明冲突不在 Sanctum 本身,而在你项目根目录硬锁了 Guzzle 6.x。下一步就该查谁在 require Guzzle 6 —— 运行 composer why guzzlehttp/guzzle。
- 这个命令只看已安装/已声明的依赖,不试错、不回溯,响应快
- 如果输出里带
require-dev条目(比如phpunit/phpunit),大概率是开发工具拖累了生产依赖 - 注意区分
prohibits(谁不让装)和depends(谁在用它),前者才是冲突源头
composer show --tree 是依赖关系的“X光片”
当你怀疑某类包(比如日志、HTTP 客户端、事件总线)被多个路径悄悄拉进来,composer show --tree 能展开整棵依赖树,一眼看出版本是否被多处锁定。
配合 grep 快速定位关键节点,例如:composer show --tree | grep -A2 -B2 monolog,能看清:
- 哪个包显式 require
monolog/monolog - 哪个子依赖又通过
replace或conflict把它踢出了可选范围 - 有没有 dev 包(如
infection/infection)把高版本间接带进主依赖树
特别注意树中重复出现但版本不同的同一包——那是冲突前兆,不是错误现场。
composer install --no-dev 是最轻量的冲突过滤器
很多冲突只在 require-dev 启用时爆发。用 composer install --no-dev 可以快速验证:去掉开发依赖后,主业务依赖能否干净安装。
- 如果成功,说明问题出在 dev 工具链里,比如
phpstan/phpstan对 PHP 版本或底层库约束极严 - 此时不要直接删
require-dev,而是逐个注释掉可疑项,再composer update --dry-run -v看哪一行触发失败 - 某些工具(如
larastan)会强制要求特定 Laravel 版本,和你当前框架不匹配时,它就是那个“不声不响卡死整棵树”的包
composer diagnose 不是摆设,它真能提前预警
composer diagnose 默认只检查基础配置,但加 -v 后会扫描平台兼容性、锁文件完整性、以及部分已知的约束矛盾模式。它不会解决冲突,但能指出风险点:
- 提示
platform.php和当前php -v不一致 —— 这是多 PHP 版本项目最常见的隐形冲突源 - 发现
composer.lock里有已被弃用(abandoned)的包,而新引入的包已不再兼容它 - 警告某些包的
conflict字段和你正在尝试安装的版本直接互斥
真正容易被忽略的是:这个命令不报错,不代表没风险。它输出的每一条 WARNING 都对应一个未来某次 update 可能突然崩掉的点。











