缩进代表直接 require 关系,每级缩进(通常两个空格)表示上层包在 composer.json 中明确定义了对下层包的依赖;它不反映重要性、加载顺序或运行时调用链,仅是声明依赖路径的视觉表达。

Composer 不区分“主依赖”和“次要依赖”——所有 require 条目在依赖解析中地位完全平等,最终版本由 SAT 求解器统一约束决定,不是靠书写顺序或层级深浅控制。
composer show -t . 显示的缩进到底代表什么
缩进是纯文本依赖路径的视觉表达:每级缩进(通常两个空格)表示「直接 require 关系」。例如 guzzlehttp/guzzle 下缩进出现 psr/http-client,说明 Guzzle 的 composer.json 里明写了 "require": {"psr/http-client": "^1.0"}。
常见误读是把缩进当“重要性”或“加载优先级”,但它和自动加载、运行时调用链、classmap 覆盖逻辑完全无关。
- 同一包在不同缩进深度重复出现(如一次在 2 级、一次在 4 级),大概率是被多个上游包分别引入,版本不一致时容易触发冲突
-
composer show -t .默认只扫描require,require-dev中的包不会出现,除非被某个生产依赖间接带入 - 终端宽度太小会导致缩进错位,建议加
| less -S查看:composer show --no-dev -t . | less -S
composer depends 和 composer show --who 的核心区别
composer depends 是反向依赖分析命令,回答“谁把我拉进来了”,但它默认只显示直接依赖链,且在 Composer 2.4+ 中属于实验功能、默认关闭;而 composer show --who 是稳定、确定、不绕弯的替代方案。
-
composer show --who psr/log扫描所有已安装包的require和require-dev字段,列出直接声明了该包的包名(比如monolog/monolog) - 加
--no-dev可过滤掉开发依赖:composer show --who --no-dev psr/log - 结果为空 ≠ 没人用 —— 可能是通过虚拟包(如
psr/log-implementation)间接提供,此时应回头查composer show -t .全局结构
为什么你写的 require 未必能“压住”间接依赖的版本
Composer 的依赖解析不是“先装主依赖、再处理子依赖”,而是把所有约束(包括你写的 require、别人包里的 conflict、PHP 版本要求等)统一建模成逻辑公式,交给 SAT 求解器找一组满足全部条件的版本组合。
- 你写
"laravel/framework": "10.40.0",但某个间接依赖硬性要求"laravel/framework": "^9.0",求解器会直接报错,而不是取最大值或忽略 - 报错
Your requirements could not be resolved...时,别改composer.json顺序,先用composer why-not laravel/framework:10.40.0查谁在拦路 -
require-dev中的包只参与开发环境求解,不影响composer install --no-dev的结果;但一旦你在require-dev里写了和require冲突的约束,它仍会参与全局求解
真正容易被忽略的是:你看到的缩进树,只是声明关系的快照;它不体现版本约束来源、不反映虚拟包实现、也不展示 replace 或 provide 的替代行为。要定位真实冲突,得交叉比对 composer show -t、composer show --who 和 composer why-not 的输出,而不是盯着某一层缩进猜逻辑。


















