Class not found 根本原因是 vendor/autoload.php 中硬编码的 DIR 路径错位,导致 PSR-4 映射指向错误目录;复制/共享 vendor 会使其失效,必须通过 composer install --discard-changes 精准还原。

vendor 目录出现 Class not found、Cannot declare class 或 autoload 失效,基本可以断定是路径错位或版本混用导致的自动加载器崩溃,不是文件丢了,而是 Composer 不知道该加载谁。
为什么 vendor 复制/共享后 Class not found
根本原因不在文件缺失,而在 vendor/autoload.php 里硬编码了 __DIR__。一旦你 cp -r vendor 到另一台机器、挂载宿主机 vendor 到容器、或让多个项目共用同一目录,__DIR__ 指向的就不是真实路径,PSR-4 映射全指向空目录。
常见现象包括:
Class 'MonologLogger' not foundCannot declare class SymfonyComponentConsoleApplication- 明明
vendor/monolog/monolog目录存在,但 new 时直接报错
这不是“能不能避免冲突”的问题,而是“谁在加载”和“Composer 认为该加载谁”的问题。禁用直接复制 vendor 是底线,没有例外。
composer install 报 “uncommitted changes in vendor/” 怎么办
这是 Composer 的保护机制,不是卡住,是明确中止:只要你改过 vendor/ 下任意一个文件(哪怕只是加了 var_dump()),它就拒绝继续执行,防止覆盖后无法追溯。
安全解法只有一条:
- 运行
composer install --discard-changes—— 它会按composer.lock精准还原每个包的原始状态,比rm -rf vendor && composer install更快、更稳,且保留 autoload 缓存结构 - 别用
composer dump-autoload或composer clear-cache试图绕过,它们根本不检查 vendor 文件内容 - 如果要用
update,务必加--discard-changes,否则它先更新再丢弃,会改composer.lock,风险更高
删了 composer.json 却还留在 vendor/ 里
执行 composer remove vendor/package 后目录还在,不是 bug,是设计行为:Composer 只改声明(composer.json 和 composer.lock),不碰磁盘,物理删除必须靠 install 或 update 触发同步。
真正清理残留的三步顺序不能错:
- 确认
composer.json的require和require-dev里已彻底删掉该包名 - 运行
composer update --with-dependencies(推荐)或composer install—— 前者只更新被修改依赖及其子依赖,更可控;后者要求composer.lock已同步更新 - 验证:
ls vendor/看目录是否消失,composer show vendor/package是否报错
注意:composer update vendor/package 是升级,不是清理;老版本 Composer(remove 后仍需补一步 install 才能清物理目录。
多个子模块共用主项目 vendor 怎么办
放弃“合并 vendor”或“共享目录”的想法。正确路径是让所有子模块放弃独立 composer install,只保留 composer.json,由主项目统一管理加载上下文。
具体操作:
- 主项目
composer.json中用"autoload": { "psr-4": { "PluginFoo\": "plugins/foo/src/" } }显式声明子模块命名空间与路径 - 子模块目录下不放
vendor/,也不单独跑composer install - 主项目执行
composer install --no-autoloader && composer dump-autoload,生成唯一vendor/autoload.php,覆盖全部命名空间
这个方案绕开了 vendor 冲突的所有根源:没跨路径加载、没版本混用、没 autoload 错位。但前提是所有子模块必须接受主项目的 autoload 统一调度,不能自己搞一套加载逻辑。











