composer-unused 是目前唯一能可靠识别“声明了但代码里真没用”的包的工具,它默认只扫描 autoload 和 autoload-dev 覆盖路径及入口文件,未配置路径(如 tests/、自定义命令)或纯运行时依赖(如 roave/better-reflection)会被误判为未使用;需通过 --include-tests 或白名单等手段修正。

直接结论:composer-unused 是目前唯一能可靠识别“声明了但代码里真没用”的包的工具,其他命令(比如 composer show --unused)根本不存在,别白费时间试。
为什么 composer-unused 扫描结果全是“used”,或者压根不报任何冗余?
它默认只扫描被 autoload 和 autoload-dev 显式覆盖的命名空间路径 + 入口文件(如 bin/console),其余目录一律跳过。
- 你的测试类在
tests/Feature/ApiTest.php里用了guzzlehttp/guzzle,但tests/没配进autoload-dev→ 工具看不到调用,误判为“未使用” - 你有自定义命令类放在
src/Command/DeployCommand.php,但该路径不在autoload的psr-4映射里 → 同样被忽略 - 项目用了
roave/better-reflection这类纯运行时反射库,代码里没有任何use或new→ 它永远被标为“冗余”,哪怕删了就炸
解决办法:要么把对应目录加进 composer.json 的 autoload 配置,要么运行时加 --include-tests 或 --additional-files=src/Command/*.php。
composer-unused 报了一堆包,哪些能删,哪些必须留?
它只负责“有没有源码引用”,不判断“业务上该不该留”。以下三类包即使被标记为 unused,也大概率不能删:
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
-
phpunit/phpunit、phpstan/phpstan:仅在phpunit.xml或 CI 脚本中出现,无 PHP 类调用 → 工具认为“没用”,但删了测试直接挂 -
symfony/dotenv、doctrine/migrations:靠.env或 YAML 配置驱动,PHP 文件里没use→ 属于框架约定依赖,删了启动报错 -
ext-redis、ext-pdo:PHP 扩展名会被当成普通包扫描 → 实际是扩展,不是 Composer 包,删了毫无意义还可能破坏依赖树
建议先建 composer-unused.php 白名单:$configuration->whitelist(['phpunit/phpunit', 'symfony/dotenv']);。
运行 composer-unused 报 command not found 怎么办?
这不是插件坏了,是安装路径或权限问题。它不走 Composer 插件机制,而是提供一个可执行二进制文件。
- 全局安装必须用:
composer global require composer-unused/composer-unused,不能漏掉/composer-unused后缀 - Linux/macOS 要确认
~/.composer/vendor/bin在$PATH里;Windows 要检查%APPDATA%\Composer\vendor\bin - 项目内使用更稳:先
composer require --dev composer-unused/composer-unused,再跑vendor/bin/composer-unused - 绝对不要用
sudo composer global require—— 权限混乱后,后续所有全局命令都可能失效
删包前最常被忽略的一步
别急着 composer remove xxx。先跑一遍:composer show -t | grep xxx,看它是不是某个已保留包的**间接依赖**。比如你留着 laravel/framework,它依赖 symfony/console,那就算 composer-unused 说 symfony/console 没被直接调用,也不能删——否则 php artisan 命令直接消失。










