composer remove 不能自动清理“过期依赖”,仅卸载显式指定的包;真正清理需先用 composer-unused 检测未被代码调用的包,再通过 composer remove + composer update 安全移除。

composer remove 不能直接清理“过期依赖”
它只卸载你明确指定的包,不会自动识别或删除那些因版本约束放宽、上游弃用、或已被其他包替代而“过期”的依赖。所谓“过期依赖”,往往只是 composer.lock 里还留着但已无任何包 require 的条目——composer remove 对这种“孤儿依赖”完全没反应。
常见错误现象:composer remove monolog/monolog 成功执行,但 vendor/monolog/monolog 目录还在,或者 composer show 仍列出一堆没被任何包引用的包。
- 真正要清理的是“未被任何 require 声明引用的已安装包”
-
composer remove必须带包名,不支持通配符或“清理所有未使用项”参数 - 运行后若没改
composer.json,下次composer install可能又拉回来
先用 composer-unused 检测真实未使用依赖
这是目前最靠谱的实操方案:它扫描全部 PHP 文件里的 use、new、class_exists 等调用痕迹,再比对 vendor/ 下已安装的包,标出“装了但从没被代码用过”的候选项。
使用场景:项目迭代久、历史依赖堆积多、想精简 vendor 体积或排查潜在安全风险。
- 安装:
composer require --dev composer-unused/composer-unused - 检测:
./vendor/bin/composer-unused --no-progress - 它默认跳过
require-dev中的包(可加--with-dev覆盖) - 注意:它不处理“被反射调用”或“字符串类名拼接”的情况,这类会误判为“未使用”
确认后用 composer remove + composer update 组合清理
检测出的包不能直接删目录,必须走 Composer 生命周期:先从 composer.json 移除声明,再更新锁文件和 vendor。否则 composer install 会报错或回滚。
参数差异:composer remove foo/bar 会自动触发 update,但只更新受影响子树;而手动 composer update --with-all-dependencies 更彻底,也更慢。
- 逐个清理:
composer remove vendor/package-name(推荐,可控) - 批量清理:把多个包名一起写,如
composer remove foo/a bar/b baz/c - 执行后务必检查
composer.lock是否删掉了对应条目,以及vendor/下目录是否消失 - 如果某包被
require-dev引用,但你只想清生产环境,得先移出 dev,再remove
清理后记得验证 autoload 和运行时行为
删包不是终点。Composer 自动加载器缓存、OPcache、甚至某些框架的编译缓存(如 Laravel 的 bootstrap/cache/*.php)可能还保留着旧类引用,导致“明明删了包,却报 Class not found”。
性能影响:减少 vendor 体积能加快部署、CI 构建和 IDE 索引;但过度清理可能让调试变难——比如删掉 symfony/var-dumper 后 dump() 就挂了。
- 清 autoload:
composer dump-autoload --optimize(线上环境必做) - 清 OPcache:
opcache_reset()或重启 PHP-FPM - 运行一次全量测试:
vendor/bin/phpunit或你的实际测试命令 - 特别留意日志、异常处理、事件监听器等隐式依赖路径










