composer 不提供原生未使用依赖检测,需借助 composer-unused 等第三方工具结合静态分析与人工验证;因 php 动态特性(如反射、字符串类名、di 注入),自动识别不可靠,移除前须多维度确认。

Composer 本身不提供原生的“未使用依赖”检测功能,composer remove 只能按手动指定包名卸载,无法自动识别哪些包在代码中实际没被引用。真要查未使用依赖,得靠第三方工具辅助,且必须结合静态分析和项目上下文判断。
为什么 composer show --unused 不存在
很多人误以为 Composer 内置类似 npm 的 npm ls --depth=0 或 depcheck 功能,但官方从未实现依赖使用率分析——因为 PHP 没有统一的 import 语法(支持 require、include、class_alias、反射、字符串类名、DI 容器动态加载等),静态扫描天然不可靠。
-
composer install和composer update只管理vendor/目录与autoload映射,不跟踪运行时调用 - 即使某个包没被任何
use或new引用,它仍可能被插件系统、配置文件或测试代码间接依赖 - 移除前必须确认:该包是否仅用于开发(
require-dev)、是否被autoload-dev加载、是否被 PHPUnit 或 Behat 等工具链依赖
推荐工具:roave/better-reflection + composer-unused
composer-unused 是目前最贴近需求的 CLI 工具,底层基于 roave/better-reflection 做符号解析,能扫描 src/ 和 tests/ 下的类引用,跳过注释和字符串中的假阳性匹配。
- 安装:
composer require --dev composer-unused/composer-unused - 基础扫描:
./vendor/bin/composer-unused(默认只检查require中的包) - 检查
require-dev:./vendor/bin/composer-unused --dev - 忽略特定包(如 Laravel 的 facade 别名):
--exclude "illuminate/support" - 注意:它不会扫描
config/*.php或routes/*.php中的字符串类名,这类需人工核对
常见误报和必须人工验证的场景
工具报告“未使用”,不等于可以安全删除。以下情况几乎必然误报:
- Laravel 的服务提供者(
AppServiceProvider中$this->app->register(...)动态注册) - Symfony Bundle 类(
bundles.php中启用但无直接 PHP 引用) - Doctrine 扩展(通过
@ORMSomething注解隐式依赖) - PSR 接口实现(如
PsrLogLoggerInterface在 DI 配置中注入,代码里只类型提示不 new) - PHP 扩展级依赖(如
ext-memcached不在composer.json,但包声明了"ext-memcached": "*")
真正安全移除的信号是:工具未报错 + grep -r 'Vendor\Package' src/ tests/ --include='*.php' 无结果 + composer depends vendor/package 返回空 + 确认 CI 流水线仍通过。别跳过最后一步。










