Composer Merge Plugin 必须与 Composer 主版本严格对齐:1.x 对应 ^1.4,2.x 对应 ^2.0;必须置于 require(非 require-dev),且 extra.merge-plugin 配置仅在根 composer.json 中生效。

composer.json 中 require 的版本约束必须匹配插件实际支持的 Composer 主版本
Composer Merge Plugin 这类插件不是普通库,它在 Composer 自身生命周期早期就介入解析流程,因此其版本必须与 Composer 二进制本身主版本严格对齐。用错版本会直接导致 composer install 崩溃或静默失效——不是报错,而是 merge-plugin 配置完全不生效。
常见错误现象:composer.json 里写了 "include" 路径,但 composer dump-autoload 后发现子配置没合并进来;或者运行 composer show wikimedia/composer-merge-plugin 显示已安装,却始终不触发合并逻辑。
- Composer 1.x → 必须用
wikimedia/composer-merge-plugin:^1.4(最高到 1.4.1) - Composer 2.x → 必须用
wikimedia/composer-merge-plugin:^2.0(如 2.0.1、2.1.0) - Composer 2.5+(当前最新稳定版)仍兼容
^2.0,但不兼容任何^1.x版本
别信“向下兼容”的说法——这个插件没有跨主版本兼容设计。升级 Composer 后第一件事就是检查并重装插件,而不是沿用旧版本。
插件依赖不能写在 require-dev 里,否则 merge-plugin 不会加载
很多人把 wikimedia/composer-merge-plugin 放进 require-dev,觉得“只是开发时用”,结果发现本地能跑,CI 构建失败,或者 composer install --no-dev 后整个项目结构乱掉。这是因为 merge-plugin 的执行时机在依赖解析最前端,它需要在 require 阶段就被识别并注册为“元插件”,require-dev 里的包在该阶段尚未载入。
正确做法只有一条:必须放在 require 根节点下,哪怕你只用它来合并 composer.local.json 这种开发配置。
- ✅ 正确:
"require": { "wikimedia/composer-merge-plugin": "^2.0" } - ❌ 错误:
"require-dev": { "wikimedia/composer-merge-plugin": "^2.0" } - ⚠️ 危险:
"require": { ... }, "require-dev": { ... }且插件在 dev 里 —— CI 环境默认跳过 dev,合并即失效
merge-plugin 的 extra 配置必须在根 composer.json,不能靠子文件继承
extra.merge-plugin 是 merge-plugin 自己读取的配置入口,它只认项目根目录下的 composer.json 中的 extra 字段。即使你在 composer.local.json 里也写了 extra.merge-plugin,它也不会被递归处理——插件不会“自己加载自己”。这是新手最容易踩的嵌套陷阱。
典型错误场景:想让 extensions/foo/composer.json 也能控制自己的合并行为,于是在里面加了 extra.merge-plugin.include,结果什么都没发生。
- 所有
include、recurse、replace等配置,必须统一写在根composer.json的extra.merge-plugin下 - 子文件(如
composer.local.json)只能提供require、autoload等常规字段,不能反向定义 merge 行为 - 路径通配符如
"extensions/*/composer.json"是有效的,但它的解析上下文永远是项目根目录
PHP 版本约束要和插件自身兼容性对齐,尤其注意 random_compat 类库
有些插件(比如老项目中残留的 paragonie/random_compat)会通过 require 引入对 PHP 版本敏感的 polyfill。如果你的项目目标是 PHP 8.2+,但插件依赖了 random_compat:>=2,Composer 可能强行拉入 9.99.99(空实现),而该版本在 Composer 2.5+ 下已被标记为废弃,甚至触发警告或拒绝安装。
这不是插件本身的错,而是你写的 require 约束没排除掉不适用的版本区间。
- PHP 7.4+ 项目:应使用
"paragonie/random_compat": " 或更精确的"^9.99.99 || ^2.0"(需配合 platform 配置) - PHP 8.2+ 项目:直接删掉
random_compat,改用原生random_bytes(),避免 polyfill 干扰插件加载顺序 - 检查方式:
composer show paragonie/random_compat看实际安装版本,再对照 Semver Checker 验证是否与当前 Composer + PHP 组合兼容
插件兼容性从来不是单点问题——它卡在 Composer 主版本、PHP 运行时、子依赖语义化版本三者的交界处。少盯一个,就会在 composer update 后某个凌晨三点突然失效。











