composer-unused是目前唯一能实际落地的检测方案,它通过反向扫描vendor中PHP源码调用痕迹(如use、new等)识别未使用依赖,但对动态加载、模板及配置中的类引用无法覆盖,需配合--scan-vendor或人工核对。

composer-unused 是目前唯一能实际落地的检测方案
它不是 Composer 内置命令,但比所有替代工具更准、更可控。原理是扫描 vendor/ 下所有已安装包的 PHP 源码,再反向查找项目中是否出现 use、new、class_exists、interface_exists 等调用痕迹——这比只看 autoload 或 require 声明靠谱得多。
常见错误现象:Class not found 报错却没被检测出来?那基本是动态加载导致的,比如 class_alias、__autoload、配置文件里硬编码的类名字符串,或者 DI 容器通过字符串反射注入。这类情况 composer-unused 默认不覆盖,得加 --scan-vendor 或手动加白名单。
它默认跳过 test/ 目录,所以测试依赖(如 phpunit/phpunit)不会被误判为冗余;但也不会识别 Twig 模板、Blade、YAML 配置里的类引用——这些必须人工核对。
安装和运行只需三步,但参数选错就白跑
执行以下命令:
composer require --dev phpstan/phpstan<br>composer require --dev composer-unused/composer-unused<br>./vendor/bin/composer-unused --no-progress
--no-progress 能避免终端刷屏干扰判断;如果你的项目用了 require-dev 里的包(比如 laravel/pint 在 CI 中调用),要加 --with-dev,否则它默认忽略所有开发依赖。
注意:它不处理“字符串拼接类名”或“call_user_func 动态调用”,这类会直接标为“未使用”,但实际可能在运行时触发——得结合日志和监控确认是否真冗余。
别信 depcheck,它在 PHP 8+ 和 Composer 2.5+ 上基本失效
depcheck 是个已停止维护的老工具,典型问题包括:
- 对 PHP 8 的联合类型、属性类型等语法解析失败,大量误报
- 默认把所有
require-dev包当冗余,哪怕你写了 200 个测试用例 - 不理解 Symfony 的
Application::add()这类动态注册机制,会把symfony/console标为未用 - 无法兼容 Composer 2.5+ 插件 API,装上可能导致
composer install报Plugin Manager is not available
它也没有路径排除选项,没法跳过 docker/、scripts/ 这类非 PHP 执行目录,结果噪音极大。
检测出的包不能直接删,必须走 Composer 生命周期
检测只是第一步,清理必须严格按流程来:
- 先确认输出里每个包确实没被用到(尤其检查配置、模板、容器绑定)
- 用
composer remove vendor/package删除声明,它会自动触发update并重算子树 - 不要手动删
vendor/vendor/package目录,否则下次composer install会因锁文件与实际不一致而报错或回滚 - 如果想连带更新整个依赖图,再补一句
composer update --with-all-dependencies,但代价是慢且易冲突
真正难处理的是那些“框架约定必须存在但生产环境不执行”的包,比如 laravel/tinker。它看起来没被代码调用,但删了会让 php artisan tinker 命令彻底消失——这种得靠文档和框架规范判断,工具无解。


















