composer why 默认只显示一级直接依赖,无法揭示真实源头;需加 --tree 参数展开完整依赖链,才能定位到 composer.json 中的顶层声明。

composer why 能直接告诉你某个包为什么被安装,但默认只显示一级依赖来源,容易误判真实原因。
为什么 composer why vendor/package 有时查不到真正源头?
Composer 的依赖解析是递归的,composer why 默认只展示「直接 require」该包的包,不展开传递依赖链。比如 monolog/monolog 可能被 laravel/framework 间接拉入,但 composer why monolog/monolog 却只显示 laravel/framework —— 而你真正想问的是:“为什么我项目里装了 laravel/framework?”
- 它不自动向上追溯到
require在composer.json中的顶层声明 - 如果包被多个路径引入,它只随机选一个路径展示(无
--tree时) - 对
require-dev中的包,它默认不区分环境,可能漏掉开发依赖触发点
用 --tree 展开完整依赖路径
加 --tree 参数才能看到从根 composer.json 到目标包的逐层引用链,这是定位“谁真正决定要装它”的关键。
composer why --tree monolog/monolog
输出类似:
monolog/monolog 2.10.0
└── laravel/framework 10.48.12
└── your-project-name dev-main
说明:最终源头是你的项目自身(即 composer.json 中写了 "laravel/framework": "^10.0")。
JTBC CMS(5.0) 是一款基于PHP和MySQL的内容管理系统原生全栈开发框架,开源协议为AGPLv3,没有任何附加条款。系统可以通过命令行一键安装,源码方面不基于任何第三方框架,不使用任何脚手架,仅依赖一些常见的第三方类库如图表组件等,您只需要了解最基本的前端知识就能很敏捷的进行二次开发,同时我们对于常见的前端功能做了Web Component方式的封装,即便是您仅了解HTML/CSS也
- 路径末尾的
your-project-name dev-main表示该包是因你项目顶层 require 被拉入 - 若某行末尾是
[dev],表示它来自require-dev - 若路径中断在某个包名后没继续,可能是该包用了
replace或provide声明替代了目标包
配合 composer show 验证提供关系
有些包并不真正包含代码,只是用 provide 声明自己“提供了”另一个包的能力(如 psr/log-implementation)。这时 composer why psr/log-implementation 会失败或返回空,因为它是虚拟包。
- 先运行
composer show --platform查看平台包(含psr/*等虚拟包) - 再用
composer show vendor/package看它的provides字段,确认是否声明了你要查的目标 - 若目标包是
provides出来的,composer why不会追踪——它只查真实安装的包
常见误操作与绕过技巧
遇到 Command "why" is not defined.?那是 Composer 版本太低:composer why 从 Composer 2.1 开始内置,1.x 用户需升级或改用 composer depends(旧版别名,行为一致)。
- Windows 下 PowerShell 可能因
-被解析出错,改用composer why --tree "monolog/monolog"加引号 - 想查已被卸载但曾存在的包?
composer why无效,得翻composer.lock手动搜"monolog/monolog"后的"source"或"require"字段 - CI 环境中发现某包莫名出现?优先跑
composer why --tree package-name 2>/dev/null || echo "not found"避免因报错中断流程
真正难的不是命令怎么敲,而是分清「谁声明了依赖」和「谁实际提供了实现」——尤其当 provide、replace、平台包混在一起时,--tree 输出里的每个箭头都得手动对回 composer.json 和 composer.lock 才算闭环。









