Composer本身不提供多租户依赖隔离能力,唯一可行方案是为每个租户生成独立composer.json+vendor目录,并运行时用ClassLoader::addPsr4()动态注册命名空间;动态字段仅限name、require、autoload,安装须加--no-scripts -d指定目录,运行时需include_once租户autoload.php并管理注册顺序。

Composer 本身不提供多租户依赖隔离能力——它只认当前目录下的 composer.json 和 vendor/,没有租户上下文、不读环境变量、也不支持运行时切换依赖树。所谓“隔离”,全靠你手动控制路径、加载时机和执行边界。
为什么不能在 composer.json 里写动态包名
像 "vendor/{$tenant}/package": "^1.0" 这种写法会直接触发 Invalid package name 错误。Composer 解析 composer.json 是纯静态文本阶段,不执行 PHP,也不识别变量语法。常见错误包括:
- 本地改完 JSON 手动测试能跑,CI/CD 里
composer install直接失败 - 误以为
.env或环境变量能在require字段生效,实际完全无视 - 用
composer dump-autoload试图扫描新模块路径,但该命令只处理autoload块声明的路径,对运行时注册无效
每个租户必须有独立 composer.json + vendor 目录
这是唯一可行的构建时隔离路径。核心不是让 Composer “支持多租户”,而是阻止它把不同租户的依赖混在一起。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 动态生成时只允许变动
name(如tenant/123)、require(白名单校验后注入)、autoload(如"Tenant\123\" => "src/tenants/123/") - 禁止动态字段:
scripts、autoload-dev、config.process-timeout—— 这些属于部署控制层,不该由租户输入决定 - 安装命令必须加
--no-scripts --no-interaction -d tenants/123,否则默认写入当前目录,且全局钩子可能污染其他租户 - 运行时不能
require vendor/autoload.php,而要include_once 'tenants/123/vendor/autoload.php',并注意ClassLoader注册顺序(先租户后主项目)
租户专属模块必须靠运行时 addPsr4() 加载
私有模块(如 tenant-a/feature-x)不能进根项目 composer.json,也不能靠 require 字段拉取——得绕过静态依赖,走运行时路径绑定。
- 模块需符合 PSR-4 结构,例如
modules/tenant-a/src/FeatureX/Handler.php对应命名空间AppTenantModulesAFeatureX - 在租户上下文初始化处调用
$loader->addPsr4('AppTenantModulesA', base_path('modules/tenant-a/src/')) - 必须检查是否已注册:
in_array('AppTenantModulesA', array_keys($loader->getPrefixesPsr4())),否则重复注册会污染 autoload 缓存 - PHP-FPM 下每个 worker 进程需独立执行注册逻辑;旧进程不会自动感知新模块,这不是缓存问题,是 ClassLoader 实例生命周期问题
COMPOSER_CACHE_DIR 和 COMPOSER_VENDOR_DIR 必须按租户隔离
缓存和 vendor 目录若被多个租户共享,会导致权限冲突、下载中断、类加载错乱。
- CI 构建时应
RUN mkdir -p /root/.composer/cache-tenant-b && COMPOSER_CACHE_DIR=/root/.composer/cache-tenant-b composer install - 禁止在 Docker 中挂载全局
~/.composer/cache到多个构建任务 - 不要设置
COMPOSER_VENDOR_DIR环境变量,它会让所有项目往同一位置写入,覆盖彼此的autoload.php - Web 服务器的
root必须严格指向各租户自己的public/,不能跨项目共享入口文件
最易被忽略的是 ClassLoader 生命周期和进程边界——addPsr4() 只对当前 PHP 进程生效,而 Composer 的缓存、锁文件、autoload 映射全都是文件系统级的静态产物。隔离不是配置出来的,是路径、时机、作用域共同约束出来的结果。

















