Composer不支持同一插件多版本,冲突是约束无法共存而非安装失败;运行composer why-not可定位阻断链,type必须为"composer-plugin"且autoload需严格符合psr-4规范。

Composer 不支持为同一插件安装多个版本,所有扩展必须收敛到一个满足全部约束的版本;冲突不是“没装好”,而是约束之间根本无法共存。
composer require 插件时直接报错:Conclusion: don't install xxx
这不是网络或权限问题,是 SAT 求解器明确告诉你:当前 composer.json 里所有依赖(包括根项目、已装包、新插件)提出的版本要求,找不到任何一个交集。
- 先别删
vendor/或composer.lock——这会让真实依赖图丢失,后续更难复现 - 运行
composer why-not vendor/plugin-name:version,它会逐层列出阻断该版本的每个依赖链,比如:
→my/projectrequiresphp: ^7.4
→symfony/consolerequiresphp: >=8.0
→vendor/plugin-namerequiresphp: >=8.1 - 检查
composer.lock中该插件当前实际安装的版本,再用composer show vendor/plugin-name看它 require 哪些其他包——常有隐藏的间接依赖在拖后腿
插件类不加载、activate() 方法完全没执行
现象是 composer require 成功、vendor/ 里有文件,但插件逻辑零触发。核心原因几乎全是 autoload 或声明配置错误。
-
composer.json中type必须严格为"composer-plugin",写成"plugin"或漏掉都会被忽略 -
extra.class的值必须是完整命名空间 + 类名,且末尾不能有多余空格;大小写必须与文件路径完全一致(Linux 下敏感) -
autoload必须用psr-4,且映射路径末尾带反斜杠:"My\Plugin\": "src/"(不是"My\Plugin": "src/") - 运行
composer dump-autoload -o后,手动打开vendor/composer/autoload_psr4.php,确认你的命名空间是否真被写进去了
多个团队共用同一插件,但各自 require 不同版本
当 A 团队 require vendor/plugin:^2.0、B 团队 require vendor/plugin:^3.0,Composer 不会“各装各的”,而是在整个项目中强制选一个版本——通常是最高兼容的那个,但也可能因其他约束被迫降级到 v1.x。
- 不要靠
conflict字段“提醒”别人别用高版本,它会全局生效,哪怕你没直接 require 那个包,只要间接拉进来就报错 - 私有插件升级前,必须同步更新
CHANGELOG.md中的 Breaking Changes,并在composer.json的require里显式声明对宿主框架的最低版本要求(如"laravel/framework": "^10.0") - 如果插件本身要适配多框架(Laravel / Symfony / Yii),别在同一个包里硬塞所有适配逻辑;按框架拆成
vendor/plugin-laravel、vendor/plugin-symfony等子包,用replace统一声明能力边界
CI 流水线里插件行为不一致
本地能跑、CI 报错,90% 是因为平台环境校验被绕过或未启用。
- CI 脚本里禁止出现
composer update或--ignore-platform-reqs;必须用composer install --no-interaction,确保完全复现composer.lock中的环境假设 - 插件若依赖特定 PHP 扩展(如
ext-gmp、ext-openssl),在 CI 镜像中显式安装,而不是靠composer install自动检测 - 某些插件在
post-autoload-dump事件里生成代码,但 CI 中composer install默认跳过 autoload 事件——加--no-scripts就会彻底失效;确认是否真需要该脚本,否则应在pre-autoload-dump或独立命令中处理
最易被忽略的一点:插件的 activate() 方法里不要做耗时操作(如远程请求、大文件读取),它在每次 composer install 或 update 时都会同步执行;一旦超时或失败,整个 Composer 命令就卡住,且无明确错误提示。


















