在PHP项目开发中,Composer作为依赖管理工具,其依赖关系的查询与梳理是开发者经常面对的任务。许多开发者希望找到一个通用的命令来解决所有依赖查询问题,但往往在几个功能相似却各有侧重的命令间感到困惑。理解每个命令的适用场景和限制,是高效管理项目依赖的关键。
核心结论先行,助你快速掌握:要查看项目完整的依赖树状结构,应使用 composer show --tree;若需追溯某个特定包被谁引入,则应优先选择 composer why --tree 或 composer show --who。至于 composer depends 命令,它是一个默认关闭的实验性功能,存在识别盲区,日常使用中容易导致误判,通常不建议作为首选。

为何 composer depends 常常查询无果?
该命令自Composer 2.4版本引入,且默认处于未启用状态。使用前必须手动开启实验性功能:composer config experimental.show-depends true
否则,直接执行类似 composer depends monolog/monolog 的命令,要么会返回错误,要么没有任何输出,令人困惑。
即便成功启用,该命令也存在若干固有缺陷,使其难以胜任复杂的依赖分析:
- 当某个包通过
provide声明提供了虚拟包(例如声明"psr/log": "*")时,它不会将此提供者识别为依赖方。 - 对于使用了
replace声明或本地path类型仓库的包,其识别能力基本失效。 - 对于仅在
require-dev中声明但尚未实际安装到vendor/目录的开发依赖包,它会直接视其为不存在。
本质上,composer depends 仅能查找那些“明确声明了直接require”的包。然而Composer自身的依赖解析机制必须处理虚拟包(provide)和包替换(replace)等复杂场景。该命令选择性忽略了这些现实情况,导致其返回的结果不完整,甚至可能产生误导。
composer why --tree:追溯依赖引入路径的利器
若想查明 monolog/monolog 为何出现在你的项目中,仅使用 composer why monolog/monolog 可能信息不足。默认输出可能只显示直接依赖者是 laravel/framework。但你真正需要确认的是:这个依赖的最终源头是否是你自己在项目根目录的 composer.json 中明确引入的?
此时,必须添加 --tree 选项以获得完整链路:
- 执行
composer why --tree monolog/monolog,如果输出结果的末端显示为your-project-name dev-main,则表明该依赖的源头是你自己的项目。 - 若末端带有
[dev]标记,则说明它来源于require-dev部分的开发依赖。 - 有时依赖树会在某一层级中断(例如停在
symfony/console不再向下展开),这通常是正常现象。这可能是因为上层包通过provide声明了某个接口,而实际实现包(如psr/log)被“虚拟”提供了,因此依赖链在此处被视为已满足,不再继续追溯。
请记住,若不使用 --tree 选项,你只能看到依赖链中的一环,如同只查看了半张地图,无法洞察全局。
composer show --who:快速定位直接依赖声明者
如果你想快速了解当前已安装的包中,有哪些在其自身的 composer.json 里直接声明了 require "psr/log",那么 composer show --who 是最佳选择:
composer show --who psr/log:此命令会列出所有直接require该包的包,包括开发依赖(require-dev)。composer show --who --no-dev psr/log:添加--no-dev选项可以排除开发依赖,仅关注生产环境的直接依赖关系。
需要注意的是,--who 选项的设计初衷是仅显示“直接声明者”。例如,依赖链为 A → B → C,查询包C时,它只会显示B,而不会显示A。这并非缺陷,而是其设计目标:它回答的问题是“谁的composer.json文件里写了这行require”,而非“谁最终在运行时加载了它”。
如果查询结果为空,切勿立即断定此包无用并计划删除。更稳妥的做法是运行 composer show --tree | grep psr/log,查看该包在整个项目依赖树中的位置。很可能,它是被某个包通过 provide 机制间接提供的。
评估未安装的包:使用 --remote 选项进行预分析
在决定是否安装一个新包(例如 doctrine/orm)之前,你可能会担忧它会引入大量额外的、或版本陈旧的依赖。实际上,你无需通过先require再remove的方式来试探。
composer show --remote --tree doctrine/orm:此命令可查看该包在远程仓库(如Packagist)中声明的完整依赖树。composer show --remote --direct doctrine/orm:如果只想查看其自身composer.json中第一层的直接依赖(require)列表,可使用此命令。
此类操作仅读取Packagist的API元数据,完全不会影响本地的 vendor/ 目录和 composer.lock 文件,既安全又高效。但必须注意一个关键点:远程信息不包含版本冲突分析。你看到的依赖树是基于该包声明的理想状态,实际安装时,可能会因与现有包的版本约束冲突而导致安装失败或发生版本降级。
最后,一个至关重要的前提是:上述所有命令的有效执行,都依赖于当前目录下存在一个有效的 composer.json 文件。对于需要分析已安装依赖的命令(如 --tree),还需要有效的 composer.lock 文件;对于查询远程信息的命令(--remote),则需要网络连接通畅。在开始任何依赖梳理工作之前,先确认这些基础条件,往往能事半功倍,避免无效操作。
