Composer无批量删失效包的安全命令;composer gc仅删vendor中lock未声明的目录,不处理缓存或代码未使用的包;真正卸载需用composer remove(2.2+推荐),配合composer-unused检测未use包,并手动清理配置与缓存。

Composer 没有“批量删除失效包”的安全命令,所谓“失效”必须人工验证是否被任何依赖链引用;composer gc 也不是清理失效包的工具,它只删 vendor/ 中未被当前 composer.lock 引用的目录,不碰缓存、不判断逻辑有效性。
为什么 composer gc 看起来没用?
这个命令实际作用非常窄:
-
composer gc只扫描vendor/目录,对比当前composer.lock文件,把 lock 里没声明的包文件夹删掉 - 它完全不管
~/.composer/cache/里的 ZIP 或 source 缓存(哪怕你半年前装过又删了,缓存还在) - 它也不管“某个包虽在 lock 里,但项目代码里根本没 use 过、也没被其他包 require”——这种才是用户常说的“失效包”,但
gc对它视而不见 - 如果你刚执行过
composer remove却发现vendor/xxx还在,那不是gc没运行,而是remove本身就不负责物理删除(见下文)
composer remove pkg1 pkg2 才是批量删包的正解
这是 Composer 2.2+ 唯一推荐的原子化卸载方式,比手改 composer.json 或循环调用 remove 安全得多:
- 多个包名用空格分隔:
composer remove spatie/laravel-permission laravel/sanctum nunomaduro/collision,不要加引号、逗号或版本号 - 它会一次性更新
composer.json、composer.lock、vendor/和自动加载映射;任一环节失败,全部回退 - 如果某包被其他已安装包硬依赖(比如
symfony/http-client依赖guzzlehttp/guzzle),命令会中止并明确提示谁在引用它——这不是报错,是保护机制 - 删完后
vendor/下对应目录可能仍存在,这是设计行为:物理清理由后续的composer install或composer update触发
真正想清“没被代码用过的包”,得靠 composer-unused
composer remove 和 composer gc 都不扫描 PHP 代码,所以无法识别“装了但从没 use 过”的包。这时需要第三方工具:
- 安装:
composer require --dev composer-unused/composer-unused - 检测:
./vendor/bin/composer-unused --no-progress(默认忽略require-dev,加--with-dev可包含) - 注意局限:它无法识别反射调用(
class_exists('FooBar', false))、字符串拼接类名($cls = 'App\'. $name;)等动态用法,这类会被误标为“未使用” - 检测出的包不能直接删目录,必须走
composer remove vendor/package+composer install流程,否则autoload映射和锁文件会不一致
删完还要手动检查三件事
Composer 不会替你擦屁股:
- 检查
config/app.php(Laravel)或类似框架配置文件里是否还注册了已删包的service providers、aliases或providers键——残留会导致启动时报Class not found或config:cache失败 - 确认
composer.json的autoload.psr-4或autoload.files段没硬写已删包的路径,否则dump-autoload会失败 - 某些环境(Docker、CI)启用了 OPcache 或框架编译缓存(如 Laravel 的
bootstrap/cache/config.php),删包后要手动清这些缓存,否则旧类仍可被加载
最易被忽略的点:删包操作本身不触发物理文件清理,vendor/ 目录残留是常态;但很多人以为“remove 成功 = 包没了”,结果在 CI 构建或部署时因 autoload 映射未刷新、缓存未清、配置未删,导致运行时异常——这些都不是 Composer 的问题,而是操作链没走完。











