查依赖树用 composer show --tree,查谁依赖某包用 composer depends(≥2.5)或 composer why --tree,查自身声明需加 --tree;输出混乱因默认不区分直接/间接依赖且含 dev 包,应加 --direct、--no-dev 或指定包名精准查看。

直接说结论:查依赖树用 composer show --tree,查谁在依赖某个包用 composer show --who 或 composer depends(≥2.5),查自己项目哪行声明了它必须加 --tree 参数。
为什么 composer show --tree 输出混乱、找不到关键路径
默认不区分直接/间接依赖,也不过滤开发包,整个 vendor 的依赖全摊开,monolog/monolog 可能混在 phpunit/phpunit → sebastian/exporter → symfony/polyfill-php80 的路径里,根本看不出是不是你主动 require 的。
- 加
--direct只看composer.json里require和require-dev显式写的包:composer show --tree --direct - 查具体包的下游依赖链,直接指定名字:
composer show --tree guzzlehttp/guzzle,它会从 Guzzle 开始向下展开,不是从 root 扫全量 - 生产环境分析必须加
--no-dev:composer show --tree --no-dev,否则phpunit拉进来的旧版symfony/polyfill会干扰判断 - 终端太窄时缩进错位?用
composer show --tree --no-dev | less -S,-S关闭自动换行
composer depends 查不到包,但 ls vendor/xxx 确实存在
最常见原因是:该包没被任何已安装包在 composer.json 里显式 require,而是被某个已安装包的子依赖“悄悄带进来”的——比如 laravel/framework 依赖 symfony/console,而后者又依赖 psr/log,但你的项目没直接写 psr/log。
- 先确认 Composer 版本 ≥2.5:
composer --version,低于就composer self-update -
composer depends默认不显示 root 项目自身,加--all才能看到是不是你composer.json里写的:composer depends --all psr/log - 如果仍为空,说明它来自未声明的路径(如
pathrepo 或手动复制),改用composer show --tree | grep psr/log定位层级,再对上层包执行composer show --tree upper/package逐级上溯 - 注意包名大小写和斜杠必须完全匹配,
monolog/monolog≠Monolog/monolog≠monolog
想定位“为什么我项目里装了这个包”,只用 composer why 不够
composer why vendor/package 默认只返回一级来源,比如查 monolog/monolog 可能只输出 laravel/framework,但你真正想知道的是:“我自己的 composer.json 哪一行写了它?” 这时候不加 --tree 就等于白查。
立即学习“PHP免费学习笔记(深入)”;
- 必须用
composer why --tree monolog/monolog,末尾出现your-project-name dev-main才说明源头是你自己项目的require - 结尾带
[dev]表示来自require-dev,上线前得重点排查 - 如果树在某一层中断(比如停在
laravel/framework就没了),可能是它用了provide声明虚拟包,此时composer show --tree不会展开下游,得回头查该包的composer.json - 依赖冲突时
--tree显示的是妥协后的版本快照,不是你写的约束。要找原因,得配composer prohibits vendor/package:version看谁在阻止升级
依赖树里同一包出现多次,缩进深度不同意味着什么
缩进代表声明依赖层级,不是加载顺序或重要性。每多两个空格,就表示下一层是上一层的直接子依赖。比如 guzzlehttp/guzzle 下缩进出现 psr/http-client,说明 Guzzle 的 composer.json 明确写了 "psr/http-client": "^1.0"。
- 同一包在不同缩进深度重复出现(如一次在 2 级、一次在 4 级),大概率是被多个上游包分别引入,版本不一致时易引发冲突
- 输出里带
(required by ...)提示,说明它是隐式依赖,没出现在你项目composer.json里,不能直接remove - 星号
*表示该包是通过replace或provide虚拟提供的,比如psr/log-implementation实际由monolog/monolog实现 -
composer show --tree不显示版本号,只显示包名。要看具体版本,得单独跑composer show vendor/package
真正麻烦的不是命令不会用,而是缩进本身不解决路径歧义——当一个包被五个不同路径引入,composer show --tree 只给你列出来,数空格确认层级是否一致,还得自己判断哪个路径才是你可控的升级入口。



















