这是预期行为;composer remove或手动改composer.json后仅更新声明和锁文件,不删vendor中文件,需依次执行:确认包已从require/remove-dev彻底移除、运行composer install同步、再执行composer dump-autoload -o重建自动加载映射。

composer.json 修改后 vendor 还有旧包?这是预期行为
不是缓存没清干净,而是 composer remove 或手动改 composer.json 后,Composer 默认不删 vendor/ 下的文件——它只更新声明和锁文件,物理同步要靠后续安装命令触发。尤其在 Composer 2.1 及更早版本中,这属于设计逻辑,不是 bug。
真正该执行的三步清理动作
顺序不能错,否则残留必现:
- 确认目标包已从
composer.json的require或require-dev中**完全移除**(注意大小写、斜杠方向、是否拼错 vendor 名) - 运行
composer install—— 这是最稳妥的同步方式;composer update会升级其他包,不适合纯清理场景 - 补上
composer dump-autoload -o—— 否则vendor/composer/autoload_psr4.php等文件里还留着已删包的命名空间映射,类看似能加载,实则指向废弃代码
为什么只跑 composer clear-cache 没用?
composer clear-cache 清的是全局缓存目录(如 ~/.composer/cache/),跟项目 vendor/ 无关。它不影响 composer.json 修改后的同步逻辑,也不会让 Composer 主动扫描并删除已声明移除的包目录。常见误判是:删了 composer.json 里的 monolog,但 vendor/monolog/monolog 还在,就以为“缓存没清”,其实只是没走对清理流程。
容易被忽略的残留点
即使 vendor/ 目录清干净了,这些地方还可能藏着引用:
-
opcache或apcu缓存未重置:PHP 可能仍从内存里拉出旧的自动加载映射,需调用opcache_reset()或apcu_clear_cache() - 代码里硬编码的
use、new、配置注册(如 Laravel 的config/app.php中的providers)、注解(Doctrine、PHPStan)、甚至数据库迁移里的字符串类名 - 某些包带
post-remove脚本,但极少实现;别指望它自动删配置、清缓存或卸载中间件
最麻烦的不是删不掉,而是删了之后系统还“假装能用”——直到某次部署或重启才暴露 Class not found。动手前先全局搜索包名:grep -r "monolog" app/ src/ config/ --include="*.php",比反复清缓存管用得多。











