composer-unused 是最可靠的 Composer 未使用包检测工具,基于 AST 分析而非静态扫描,需按 PHP 版本选对版本(v0.12.x 要求 ≥8.1,7.4 用 v0.9.11),并排除 tests/vendor/var 等路径避免误报。

直接检测并清理 Composer 项目中未使用的包,composer-unused 是目前最可靠的选择——它不是靠静态扫描 autoload 或猜测依赖,而是通过实际代码引用分析(AST + 文件遍历),准确率远高于 depcheck 或手动 grep。
安装 composer-unused 并确保 PHP 扩展兼容
它依赖 php-parser 和 symfony/filesystem,且对 PHP 版本敏感。当前稳定版(v0.12.x)要求 PHP ≥ 8.1;若项目还在 PHP 7.4,必须降级到 v0.9.11,否则运行直接报 ParseError: syntax error, unexpected token "readonly"(因 readonly 属性引入于 PHP 8.2)。
推荐安装方式(全局):
composer global require composer-unused/composer-unused:^0.12
若已存在旧版本,先卸载再重装:
composer global remove composer-unused/composer-unused- 确认
~/.composer/vendor/bin/在$PATH中 - 运行
composer-unused --version验证
运行检测:跳过测试文件与 vendor 是关键
默认会扫描全部 .php 文件,包括 tests/、vendor/、var/ 等,导致误报“某包仅在测试中使用”,或因 vendor 内部引用污染结果。必须显式排除:
composer-unused --no-progress --exclude tests --exclude vendor --exclude var
常用组合参数说明:
-
--no-progress:关闭进度条,避免 CI 日志刷屏 -
--exclude可多次使用,支持通配符如--exclude "src/Console/*" - 若项目用
psr-4自动加载但部分类未被引用,composer-unused不会将其标记为“未使用”——它只看实际use、new、static::等调用,不看自动加载注册
识别 false positive:哪些“未使用”其实不能删
输出中列出的包,需人工二次判断。以下情况看似未使用,但删掉会导致运行时错误:
-
doctrine/annotations:未在代码中use,但被 Doctrine ORM 或 Symfony 注解解析器反射调用 -
phpunit/phpunit:虽被--exclude tests跳过,但若composer.json中是require-dev,且无其他 dev 包依赖它,composer-unused仍可能报出——此时应忽略 -
symfony/flex或laravel/pint:纯 CLI 工具型包,代码里当然不会出现use,但composer.json的bin字段或脚本依赖它 -
ext-*扩展(如ext-gd):composer-unused不检测扩展依赖,这类需查composer.json的ext-*声明或运行时extension_loaded()
安全清理流程:从 dry-run 到提交
不要直接 composer remove。标准操作链如下:
composer-unused --dry-run --exclude tests --exclude vendor
观察输出,确认列表中没有上述 false positive 类型;然后逐个验证:
- 执行
grep -r "SomeClass" src/ tests/ --include="*.php"确认真没引用 - 临时注释
composer.json中对应包,运行composer install和核心测试(./vendor/bin/phpunit --testsuite=unit) - 若通过,再执行
composer remove vendor/package-name - 提交时,建议一条 commit 清理一个包,附上验证命令和结果(例如:
# verified: no use in src/, tests/, bin/; phpunit passes)
最易被忽略的是:某些包被 composer.json 的 replace 或 provide 声明间接依赖,或被插件(如 symfony/runtime)动态加载——这些无法被 AST 分析覆盖,必须结合项目架构文档交叉确认。










