不会。composer remove只卸载显式指定的包,不递归清理仅被其依赖的“孤儿包”;需用composer-unused扫描代码引用并人工核验autoload、配置及动态调用后安全删除。

composer remove 会自动清理依赖树里的孤儿包吗?
不会。composer remove 只卸载你明确指定的包,不会递归检查并删除那些「只被刚删掉的包所依赖」的其他包。比如你删了 monolog/monolog,它之前依赖的 psr/log 如果还有别的包在用,就留下;但如果整个项目里再没别的地方 require psr/log,它就成了孤儿包——但 composer remove 不管这个。
怎么安全地找出并删掉真正的孤儿包?
得靠两步手动确认:先生成当前实际被引用的依赖图,再对比 vendor 目录里真实存在的包。推荐用社区验证过的工具 composer-unused:
- 运行
composer global require composer-unused/composer-unused(确保全局 bin 可执行) - 在项目根目录执行
composer-unused --no-interaction --no-progress - 它会扫描所有
require和require-dev,再检查 PHP 文件中是否实际用了这些类/命名空间,最后列出「声明了但没被代码引用」的包 - 注意:它不判断运行时动态加载(如
class_exists($name)或插件式扩展),这类包会被误标为“无用”
为什么不能直接 composer update --dry-run 来找孤儿包?
因为 composer update --dry-run 只模拟更新行为,输出的是「将要安装/升级哪些包」,不反映「哪些已安装包不再被任何 require 声明需要」。它甚至不会告诉你 symfony/polyfill-mbstring 是否已被其他包隐式覆盖或废弃——这属于依赖解析后的结果,不是声明层面的冗余。
更关键的是:Composer 的 lock 文件和 vendor 目录之间存在状态差。比如你手工删过某个包但没改 composer.json,--dry-run 完全感知不到。
删孤儿包前必须检查的三个地方
哪怕 composer-unused 报告某包“未使用”,也别急着删:
- 查
composer.json里是否在autoload或autoload-dev中引用了该包的路径(比如用它提供的一组辅助函数) - 看有没有
config/platform或replace配置间接依赖它(例如用ext-redis替换predis/predis,但代码里仍调用了 Predis 类) - 运行
grep -r "use.*SomeClassFromThatPackage" --include="*.php" .确认没有硬编码引用(尤其注意 traits、注解、配置文件里的类名字符串)
孤儿包本身不危险,但删错一个被运行时反射调用的包,可能只在特定请求路径下才报错,这种问题很难复现。











