composer.lock 是 Composer 项目依赖状态的唯一权威快照,必须提交至 Git;它锁定具体版本、源码 commit 及哈希校验值,确保所有环境 vendor 目录完全一致,install 严格按其执行,误删须从 Git 恢复而非重建。

Composer 依赖链不是静态结构,而是由 composer.lock 和当前 vendor/ 目录共同决定的快照;查依赖必须基于已安装状态,不能只看 composer.json。
用 composer show -t 看真实安装的依赖树
这是唯一无需插件、不依赖实验配置、且在 Composer 2.0+ 全版本稳定的命令。它读的是 vendor/ 和 composer.lock 的实际内容,不是理想化声明。
- 必须指定目标:比如
composer show -t guzzlehttp/guzzle(查 Guzzle 的下游依赖),或composer show -t .(查整个项目) - 缩进层级 = 实际安装深度:同一包若出现在两处不同缩进,说明被多个路径引入,是潜在冲突信号
- 括号里的
[7.8.1]或[dev-main]是真实安装版本,不是composer.json里写的^7.0 - 不加
--no-dev时,require-dev里的包若被生产依赖间接拉入,也会出现在树中
用 composer why -t 追溯到你自己的 composer.json
composer why 默认只返回一级上游,比如 laravel/framework;但你要知道“哪一行 require 拉进来的”,就必须加 -t。
- 输出形如:
monolog/monolog→laravel/framework→your-project-name dev-main,末尾才是你自己的项目 - 若某行结尾带
[dev],说明源头在require-dev,上线时可能被跳过 - 如果中断在中间(比如停在
symfony/console就没了),大概率是它通过provide psr/log虚拟声明,没继续解析下去 - 返回 “No dependencies” 不代表没人用——可能是被
replace或autoload隐式加载,此时应回头看composer show -t .
别碰 composer depends 和 composer tree
这两个命令要么已弃用,要么默认关闭且行为不可靠。
-
composer tree不是内置命令,是旧插件残留,现在执行会报错或静默失败 -
composer depends在 2.4+ 默认禁用,开启后对provide、path类型仓库支持差,容易漏判 - 替代方案明确:
composer show --who查谁直接require了它(干净、确定、不绕弯) -
composer show --who --no-dev psr/log可过滤掉开发期依赖,聚焦运行时真实引用者
依赖链 ≠ 代码调用链,autoload 才决定类加载顺序
看到 composer show -t 里 A → B → C,并不代表 PHP 运行时一定会按这个顺序加载类。真正起作用的是 autoload 注册顺序。
- PSR-4 声明顺序、
classmap是否启用、autoload-dev是否参与 dump,都会影响最终vendor/autoload.php的 loader 链 - 两个包都声明了
Helper类?谁先注册,谁生效——这种覆盖不报错,但行为突变 - 调试时可加
echo spl_autoload_functions();查看实际注册的 loader - 用
composer dump-autoload -o生成 classmap,能固化加载顺序(classmap 优先于 PSR-4)
最常被忽略的一点:依赖树是动态快照,受 config.platform、PHP 版本、甚至本地 composer.json 中的 replace 块影响。同一份 composer.lock,在不同平台执行 composer install,可能装出不同的树。











