composer 本身不提供运行时依赖隔离沙箱,必须手动构造路径、加载逻辑和执行边界;因php无类加载器隔离机制,同一进程加载多套vendor会触发类重声明或找不到类错误,真正可行的是分进程+独立vendor的沙箱方案。

Composer 本身不提供运行时依赖隔离沙箱,所谓“Sandbox”必须由你手动构造路径、加载逻辑和执行边界——不是开个开关就能跑两个版本的 monolog/monolog。
为什么不能靠 Composer 自动建沙箱
PHP 没有类加载器隔离机制,composer/autoload.php 是静态映射文件,一旦生成就绑定当前 vendor/ 目录结构;同一命名空间下的类只能被加载一次,第二次 require_once 无效,但类定义已存在。强行在同一个进程里加载两套 vendor/,大概率触发 Fatal error: Cannot redeclare class 或 Class not found。
-
replace、provide、conflict都只影响安装阶段的解析,不改变运行时行为 -
COMPOSER_VENDOR_DIR改的是写入位置,不是加载隔离——只要autoload.php被include进来,它注册的 PSR-4 映射就全局生效 - 即使你 fork 一个包并改名(如
myorg/monolog-legacy),也得确保业务代码里所有调用都走新命名空间,否则旧引用仍会去老 autoload 查找
可行的沙箱构造方式:分进程 + 独立 vendor
真正能隔离的,是让不同版本在不同 PHP 进程中运行,各自拥有完整且互不干扰的 vendor/ 和 autoload.php。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 每个沙箱对应一个子目录(如
./sandboxes/v1/、./sandboxes/v2/),内含独立的composer.json、vendor/和入口脚本 - 主进程用
proc_open()或shell_exec()启动子进程,传入参数并捕获 stdout/stderr,例如:php ./sandboxes/v1/bin/run.php --input=xxx - 子进程启动前清空
get_defined_constants()中可能污染的常量(如APP_ENV),避免配置泄漏 - 不要在沙箱内
require主项目代码——它可能隐式依赖主vendor/,应只暴露明确接口(如 JSON 输入 / 输出)
autoload_dev.php 是沙箱里的隐藏雷区
哪怕你用了 --no-dev 安装,只要 composer.lock 里还存着 dev 包记录,或者 vendor/composer/autoload_dev.php 文件没删干净,沙箱进程就可能加载到测试类或调试工具,引发线上环境报错。
- 构建沙箱时必须执行:
composer install --no-dev --optimize-autoloader --no-scripts,再手动确认vendor/composer/autoload_dev.php不存在 - 检查
composer.json的autoload-dev字段是否为空,否则dump-autoload仍会写入映射路径 - Docker 构建中,推荐在
RUN阶段末尾加一句:rm -f vendor/composer/autoload_dev.php
私有 SDK 的版本约束必须留出语义化余地
如果你的沙箱要接入内部 SDK(如 acme/payment-gateway),它的 composer.json 里写死 "guzzlehttp/guzzle": "7.4.5",就会锁死整个沙箱的 Guzzle 版本——哪怕你另一个沙箱需要 v8。
- SDK 的
require应写成"guzzlehttp/guzzle": "^7.4 || ^8.0",前提是代码真做了兼容处理(比如用if (method_exists(...))判断 API 差异) - 避免在 SDK 里设
"minimum-stability": "dev",这会让下游项目被迫接受不稳定分支,增加冲突概率 - 发布 SDK 时必须打 Git tag(如
v3.2.0),别依赖dev-main—— Composer 对分支名的解析策略不稳定,尤其在多沙箱共存时容易误判
沙箱不是靠配置堆出来的,是靠目录拆分、进程隔离、autoload 清理和 SDK 约束收敛四层动作共同落地的;漏掉任何一层,都可能让“隔离”变成“伪隔离”,上线后才暴露类冲突或方法缺失。










