Composer插件需在composer.json中声明"type": "composer-plugin"并实现PluginInterface,通过事件监听(如PostInstallEvent)响应命令,而非脚本事件;activate()仅初始化,deactivate()几乎不调用。

Composer 插件不是靠“注册”或“启用”命令就能生效的,它必须被声明为项目依赖并满足 type: composer-plugin,否则 composer install 根本不会加载它。
如何让 Composer 识别并加载你的插件
关键不在代码逻辑,而在 composer.json 的声明方式。Composer 只扫描已安装的包中同时满足两个条件的:一是 "type": "composer-plugin",二是类实现了 ComposerPluginPluginInterface。
- 插件包必须发布(哪怕本地用
path仓库),不能只是项目内一个文件夹 -
autoload必须正确映射到主类,例如"psr-4": {"MyPlugin\": "src/"} - 主类构造函数接收
ComposerComposer和ComposerIOIOInterface实例,这是操作依赖图和输出日志的唯一入口 - 不要在插件类中调用
dump-autoload或触发重安装——这会引发递归执行,导致Maximum function nesting level错误
activate() 和 deactivate() 的真实作用范围
这两个方法不是生命周期钩子,而是 Composer 内部管理插件实例的开关信号。它们不对应命令执行阶段,也不保证按顺序调用。
-
activate()仅在插件首次被加载时调用一次,适合做单次初始化(如绑定事件监听器) -
deactivate()几乎从不被调用——除非你手动调用PluginManager::removePlugin(),而 Composer 自身从未这么干过 - 真正响应命令行为的是事件监听:比如监听
CommandEvent(对应composer install)、PostInstallEvent等,需通过$composer->getEventDispatcher()->addListener()注册
为什么你的插件没收到 post-install-cmd 事件
因为 post-install-cmd 是脚本事件(script event),不是插件事件(plugin event)。插件无法直接监听它;想在安装后执行逻辑,必须监听 ComposerScriptEvent 的子类,但更可靠的方式是监听 PostInstallEvent(属于 ComposerPluginEvent)。
-
PostInstallEvent在依赖写入vendor/后、生成autoload.php前触发 - 若需修改自动加载规则,应在
PostAutoloadDumpEvent中操作,此时$event->getComposer()->getAutoloadConfig()已可读写 - 监听脚本事件(如
post-install-cmd)需在根项目composer.json中声明scripts,插件无法注入该配置
插件机制本质是 Composer 的扩展点,不是钩子系统。最易忽略的一点:所有事件监听器都运行在同一个进程、同一个 Composer 实例中,共享内存状态——这意味着不能假设每次命令都是干净上下文,尤其当多个插件共存时,$composer 对象可能已被其他插件修改过 autoload 配置或 repository 列表。











