每个PHP项目必须有独立composer.json和vendor目录,否则autoload冲突、类加载错乱、Class not found错误必然发生;这是Composer按项目根目录隔离依赖的设计前提,共享会导致PSR-4映射干扰、spl_autoload_register全局污染及IDE/opcache缓存固化。

每个 PHP 项目必须有独立的 composer.json 和 vendor/ 目录,否则 autoload 冲突、类加载错乱、Class not found 错误几乎必然发生——这不是配置问题,是 Composer 的设计前提决定的。
为什么不能共享 vendor 目录或 composer.json
Composer 按项目根目录解析依赖,所有 autoload 规则(PSR-4/classmap)最终都注册进同一个 spl_autoload_register 全局队列。两个项目共用 vendor/autoload.php,等于让两个 ClassLoader 实例先后调用 $loader->register(),后注册的会干扰前者的命名空间匹配逻辑。
- 现象:
new AppV1Client()被 V2 的 PSR-4 规则捕获,抛出Fatal error: Class 'AppV1Client' not found - 即使加了
include_once,ClassLoader内部的static属性(如映射表)仍会累积污染 -
unset($loader)无法卸载已注册的 autoloader —— PHP 不提供反注册接口 - IDE 和 opcache 缓存可能固化错误映射,重启 Web 服务也不一定生效
如何正确隔离:每个项目独立入口 + 手动控制 ClassLoader
关键不是“不加载”,而是“不自动注册”。绕过 vendor/autoload.php 默认的 register() 行为,改为自己掌控生命周期。
- 在项目入口(如
web/v1/index.php)中:$loader = require __DIR__.'/../v1/vendor/autoload.php'; $loader->unregister(); // 必须先解除全局注册 $loader->addPsr4('App\', __DIR__.'/../v1/src/'); $loader->loadClass('AppV1Client'); // 显式触发,不依赖自动加载 - 若需自动加载,自己注册闭包:
spl_autoload_register(function ($class) use ($loader) { $loader->loadClass($class) ?: false; });注意:这是你自己的闭包,和 Composer 默认注册的那个无关 - 绝对不要在同一个 PHP 进程里
require多个项目的autoload.php
多租户或灰度场景:动态生成 composer.json + 隔离 install
当租户间依赖版本冲突(如 A 要 monolog/monolog:^2.0,B 要 ^3.0),必须为每个租户生成专属 composer.json 并隔离 vendor/。
- 可变字段仅限:
name(建议设为tenant/{id})、require、autoload;其他如autoload-dev、scripts、config禁止动态生成 - 必须校验:
require中包名是否在白名单内,版本约束是否符合语义化(拒绝1.*.*这类模糊写法) - 安装时必须加
--no-scripts -d tenants/{id}/,避免触发全局钩子或写入错误路径 - 运行时按需
include_once 'tenants/{id}/vendor/autoload.php',且每次只加载一个
容易被忽略的细节:autoload-dev 和 --no-dev 的边界
composer install --no-dev 只跳过安装 require-dev 里的包,但不会禁用 autoload-dev 的映射规则——如果这些规则已被写入 vendor/composer/autoload_*.php,它们依然生效。
- 现象:生产环境启用了
barryvdh/laravel-debugbar,只因autoload-dev里注册了它的 PSR-4,而你没删掉use或配置中的引用 - 验证方式:
grep -r "Debugbar" vendor/composer/autoload_*.php,若命中,说明映射还在 - 真正安全的做法:上线前执行
composer dump-autoload --no-dev -o,并人工检查框架配置文件(如config/app.php)是否残留 provider











