composer-unused是当前唯一靠谱的检测未使用依赖方案,它通过扫描vendor源码并反向查找项目中use/new等真实引用痕迹来识别冗余包,但需避开symfony/polyfill类误报、配置文件类名遗漏及动态加载场景等坑。

composer-unused 是目前唯一靠谱的检测方案
Composer 自带命令完全无法识别“已安装但未调用”的包,composer show --tree只画依赖图,composer depends只能查谁依赖它,而不能回答“我项目里根本没用它”。composer-unused是当前生态中唯一持续维护、适配 PHP 8+、且原理扎实的工具:它扫描 vendor/ 下所有包的源码,再反向查找项目代码中是否出现 use、new、class_exists、interface_exists 等真实引用痕迹。
- 它默认跳过
tests/目录,不会把测试依赖误判为冗余 - 不扫描 Twig/Blade 模板、YAML/JSON 配置文件里的类名字符串(这类需人工确认)
- 对 DI 容器注入、Laravel Service Provider 注册等动态场景无感知,需结合运行时日志或
phpstan补充验证 - 安装只需两行:
composer require --dev phpstan/phpstan和composer require --dev composer-unused/composer-unused
常见误报和必须绕开的坑
运行 ./vendor/bin/composer-unused 后发现一堆“未使用”但删了就报错?大概率掉进了这几个坑:
-
symfony/polyfill-*类包几乎总会被标为“未使用”,但它在加载时注册函数别名(如array_key_first()),实际被全局调用——必须加白名单:--whitelist=symfony/polyfill-* - 配置文件里写死的类名(如 Laravel 的
config/logging.php中的'handler' => Monolog\Handler\StreamHandler::class)不会被扫描到,需手动检查配置目录 - 使用了
class_alias()或自定义__autoload()的项目,得加--scan-vendor参数,否则 vendor 内部的引用关系不会被逆向追踪 - 如果项目用了 Psalm 或 PHPStan,先跑一遍
vendor/bin/phpstan analyse,避免因类型推断失败导致误报“接口实现类未使用”
执行前必须做的三件事
跳过这三步,composer-unused 的结果基本不可信:
- 确保
composer install已执行完成,vendor/autoload.php可正常加载——否则连自己项目的类都解析不了 - 确认
composer.json中没有矛盾配置,比如"autoload"和"autoload-dev"里路径重叠、命名空间冲突,或"psr-4"路径末尾漏了双反斜杠\ - 删包前先 grep 全局:运行
grep -r 'monolog\/monolog' . --include='*.php' --include='*.yaml' --include='*.yml',覆盖代码+配置,比工具更直接
真正难判断的从来不是“有没有引用”,而是“这个引用是否在运行时才触发”。比如一个包只在某个 CLI 命令的 handle() 方法里 new 了一次,但该命令极少被调用——composer-unused 能抓到,可你得自己决定它算不算“冗余”。











