Composer 2.2+ 默认禁用插件,必须在项目根目录 composer.json 根级配置 allow-plugins 为字符串数组(如 ["symfony/flex"]),大小写敏感且不可通配;全局插件需配置 ~/.composer/config.json 中的 config.allow-plugins。

Composer 2.2+ 必须显式允许插件,否则直接报错
从 Composer 2.2 开始,所有 type: "composer-plugin" 的包默认被禁用,composer install 会直接中断并提示 "Plugin installation is disabled"。这不是配置遗漏,而是强制安全策略——你必须在项目根目录的 composer.json 中声明 allow-plugins。
常见错误是只写 "allow-plugins": true,这等于放弃安全控制;更危险的是漏掉关键插件,比如 symfony/flex 或 phpstan/extension-installer,导致 recipe 不执行或静态分析无法集成。
-
allow-plugins必须写在composer.json根级,不能放在config或extra下 - 值必须是字符串数组,包名大小写敏感、无通配符,例如:
"dealerdirect/phpcodesniffer-composer-installer",不能写成"phpcodesniffer-composer-installer" - 如果用了
composer global require安装插件,全局配置也需设config.allow-plugins(路径通常为~/.composer/config.json)
插件没加载?先确认它是否真被识别为插件
运行 composer show vendor/package-name,检查输出中是否有 types : composer-plugin。没有就说明 Composer 根本没把它当插件看——哪怕代码里有 Plugin 类、activate() 方法写得再规范也没用。
常见伪插件包括:仅提供 bin 命令的工具(如 phpunit/phpunit)、含辅助函数的库、或没声明 "type": "composer-plugin" 的包。这类包 require 后不会触发任何插件生命周期。
- 插件包自身的
composer.json必须含"type": "composer-plugin"(由作者定义,你不能靠修改它来“变”成插件) - 你的项目
composer.json中必须把该包写进require或require-dev,且已执行过composer install或composer update vendor/package-name - 若插件来自私有 Git 仓库,需在
repositories中声明type: "vcs",并确保有有效 tag(如v1.0.0)
插件类写了但 activate() 没执行?检查 autoload 和签名
即使包被识别为插件,activate() 方法也不会调用,除非它能被自动加载,且方法签名完全匹配。Composer 会静默跳过任何构造失败、autoload 失败或签名错误的插件——你不会看到报错,只会发现什么都没发生。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
最靠谱的验证方式是在 activate() 开头加一行日志:file_put_contents('/tmp/plugin-activated', 'yes', FILE_APPEND),然后运行 composer install -v 看文件是否生成。
-
extra.class字段(如果插件要求)必须指向完整命名空间类名,如"MyVendor\MyPlugin\MyPlugin",不能是短名或相对路径 - 插件类必须能被 PSR-4 或 classmap 正确加载;检查
autoload["psr-4"]是否覆盖该类路径,改完后务必composer dump-autoload -o -
activate()方法签名必须严格为:public function activate(Composer\Composer $composer, Composer\IO\IOInterface $io),参数类型错一个字符都会失效
命令没出现、事件不触发?不是插件没加载,是没暴露功能
插件加载成功 ≠ 命令可用 ≠ 事件监听生效。这两件事是解耦的:activate() 是入口,后续要手动注册命令和事件监听器。
比如你想让 composer my-command 可用,光实现 PluginInterface 不够,还必须重写 getCommands() 并返回 Composer\Command\Command 实例数组;监听 post-install-cmd 则需在 activate() 内调用 $composer->getEventDispatcher()->addListener('post-install-cmd', ...)。
- 运行
composer list查看命令是否列出;没出现说明getCommands()未返回有效对象,或返回了但类未继承Composer\Command\BaseCommand - 事件名必须是纯字符串(如
"post-autoload-dump"),不是常量(如ScriptEvents::POST_AUTOLOAD_DUMP),大小写、下划线都不能错 - 监听器回调里别 throw 异常——这会让整个
composer install报红退出,用户看不到你的提示信息
真正容易被忽略的是:插件是否生效,只取决于它是否出现在当前执行 composer 命令的那个项目的 composer.json 中,以及该命令是否触发了插件注册阶段。其他任何位置的 require,都是无效的。

















