插件开发必须区分 composer 1 和 2 的运行时环境,无法通过 "composer-plugin-api": "^1.0 || ^2.0" 实现自动兼容;需在代码中主动探测类存在性(如 class_exists('composer\script\event'))并分路径执行,避免在构造函数中直接实例化 v2 特有类,否则 v1 下会 fatal error。

插件开发必须区分 Composer 1 和 2 的运行时环境
Composer 插件无法靠 "composer-plugin-api": "^1.0 || ^2.0" 声明实现“自动兼容”。v1 和 v2 的插件生命周期、事件类路径、方法签名、内部类结构都不同,强行声明双版本会导致 Composer 自身校验失败或运行时 fatal error。
常见错误包括:Plugin X is not compatible with Composer 2、Class 'ComposerPluginCapabilityCommandProvider' not found(在 v1 下)、ArgumentCountError: Too few arguments(因 activate() 参数不匹配)。
- 在
composer.json的require中只能声明一个明确版本:"composer-plugin-api": "^1.1.0"(支持 Composer 1)或"^2.2.0"(支持 Composer 2) - 所谓“兼容旧版本”,实际是代码里主动探测并分路径执行,不是依赖 Composer 自动适配
- 所有对 v2 特有类(如
ComposerPluginCapabilityCommandProvider)或方法(如Package::getNamesWithStability())的引用,必须前置class_exists()或method_exists()判断 - 避免在
__construct()或静态初始化块中直接实例化 v2 类——v1 环境下会立即崩溃
运行时检测要覆盖关键 API 差异点
不能只判断 Composer 主版本号,得逐项验证具体能力。例如 ComposerScriptEvent 在 v1 存在、v2 已废弃;而 ComposerPluginCapabilityCommandProvider 是 v2 新增接口。两者共存于同一代码库时,必须按需加载。
典型检测逻辑如下:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
public function activate(Composer $composer, IOInterface $io)
{
if (class_exists('ComposerScriptEvent')) {
// v1 路径:注册旧事件
$dispatcher = $composer->getEventDispatcher();
$dispatcher->addListener('pre-install-cmd', [$this, 'onPreInstall']);
} else {
// v2 路径:注册 capability
$this->addCommandProvider($composer);
}
}
- 不要用
PHP_VERSION_ID或defined('COMPOSER_VERSION')判断——不可靠,且与插件 API 无关 - 检测顺序很重要:先查类,再查方法,最后查常量;避免
method_exists()在类未加载时抛出 warning - 对
Package、Link、RepositoryInterface等内部模型的操作,每次访问属性或调用方法前都应确认其存在性
platform 配置对插件本身无效,但影响其依赖解析
config.platform 只作用于项目级依赖解析,不改变插件自身的运行环境。插件代码始终在当前 Composer 进程的 PHP 版本和扩展环境下执行。如果你的插件依赖了 ext-xml,而用户环境没装,platform 不会帮你“模拟”出来。
但它会影响插件所依赖的其他包(比如插件 require 了 symfony/console):
- 若插件
require了"symfony/console": "^5.4",而项目设了"platform": {"php": "7.4.33"},Composer v2 会选symfony/console v5.4.42(PHP 7.2.5+),而非 v6.x(要求 PHP 8.0+) - 但插件主逻辑仍需自己处理 PHP 7.4 下不支持的语法(如
match表达式),platform不会做 polyfill - 插件的
composer.json中不应写"platform"——它不属于插件行为配置项,会被忽略
测试兼容性必须覆盖真实安装场景
光跑 PHPUnit 不够。插件是否真能被 Composer 1 和 Composer 2 正确识别、激活、执行命令,取决于它的安装方式和加载时机。
- 本地开发时,用
composer global require --no-plugins安装插件到全局,再分别用php74 /path/to/composer1.phar和php82 /path/to/composer2.phar测试 - CI 中需并行跑两个 job:一个用 Composer 1 + PHP 7.4,一个用 Composer 2 + PHP 8.2,各自执行
composer install后验证插件是否响应对应事件 - 不要依赖
--ignore-platform-reqs测试——它绕过的是平台约束,不是 API 兼容性问题;该参数对插件激活失败无任何帮助 - 最易被忽略的是 autoload 映射:v1 和 v2 生成的
vendor/autoload.php结构略有差异,插件若手动 require 了 vendor 内部文件,可能在某版本下找不到路径










