class_exists()返回false说明类未被autoloader注册,非命名冲突;应先验证vendor/autoload.php是否正确引入、检查autoload_psr4.php映射、运行composer dump-autoload -v确认扫描路径,并清理autoload_*.php缓存。

class_exists() 返回 false?先确认 autoload 根本没加载
这不是命名冲突,而是类压根没被注册进自动加载器。常见于漏掉 require 'vendor/autoload.php',或 Web 入口路径拼错(比如用 $_SERVER['DOCUMENT_ROOT'] 拼出旧缓存的 autoload 文件)。最简验证方式:在出错脚本开头加 var_dump(class_exists('YourClass'));。返回 false 就说明 autoload 没生效——别急着改命名空间,先查加载链。
autoload_psr4.php 里出现重复映射?检查 PSR-4 前缀重叠
Composer 不按 composer.json 中 psr-4 数组的书写顺序加载,只认“最长前缀匹配”。比如同时配了 "App\": "src/" 和 "App\Helper\": "vendor/pkg/src/Helper/",那么 new AppHelperUserService() 一定走后者;但 new AppUserService() 仍走前者。真正危险的是写两个宽泛前缀,例如都用了 "App\": "src/",这时 Composer 2.2+ 会直接报错;低于该版本则后注册的映射覆盖前注册的键,行为不可控。
- 运行
composer dump-autoload -v,观察终端是否扫到了你预期的类路径 - 删掉
vendor/composer/autoload_*.php,再执行一次dump-autoload,排除旧缓存干扰 - 搜索
vendor/composer/autoload_psr4.php,看你的类名关键词(如UserRepository)是否出现在两条及以上映射里——只有真出现多次,才是重名实锤
vendor/autoload.php 加载成功但类找不到?检查 classmap 和 PSR-4 的优先级
classmap 总是赢。只要你在 composer.json 的 classmap 字段里写了 "src/Helper.php",那么 new Helper() 就永远走 classmap,完全跳过 PSR-4 推导;而 new AppHelper() 还是走 PSR-4——它们不打架,但容易让你误判。
- 确认你没在
classmap里误录了一个同名类文件,导致它抢先拦截了本该由 PSR-4 加载的类 - 避免手动
include或require类库后再通过 Composer 引入相同类库,PHP 会报Cannot redeclare class - ThinkPHP 等框架若自定义了
extend/目录,必须在composer.json中显式声明"autoload": {"psr-4": {"extend\": "extend/"}},否则 Composer 不知道去哪找
全局安装工具引发的 autoload 冲突最隐蔽
根本原因是 PHP 自动加载器只能加载一个版本的类,而全局与项目依赖可能引入同名库的不同版本。错误信息里若出现来自 /home/xxx/.composer/vendor/ 的路径,就是最直接证据。
- 运行
composer global show,看是否装了和项目里同名或提供相同类的包(如phpunit/phpunit、symfony/console) - 临时重命名全局 vendor 目录:
mv ~/.composer/vendor ~/.composer/vendor.bak,再跑composer install—— 如果成功,基本就是它 - 彻底停用全局命令:卸载全局工具(
composer global remove friendsofphp/php-cs-fixer),改用项目级调用(./vendor/bin/php-cs-fixer)
真正麻烦的不是“怎么装”,而是“谁在加载”。只要全局和项目共用同一个类名空间,哪怕版本号看着不冲突,自动加载顺序一变,行为就不可控。把工具下沉到项目层,才是可复现、可审计、可协作的底线。











