必须写Composer插件并实现EventSubscriberInterface才能干预安装/更新流程;scripts仅支持命令前后简单回调,无法拦截或修改核心行为,且不参与依赖解析等内部事件系统。

真要干预安装/更新流程(比如校验签名、清理缓存、生成 autoload 快照),必须写 Composer 插件并实现 EventSubscriberInterface;只在 composer.json 里配 scripts,只能做命令执行前后的简单回调,无法拦截或修改内部行为。
为什么 scripts 不等于事件监听
scripts 字段声明的只是“命令生命周期钩子”,不是 Composer 内部事件系统的一部分。它不参与依赖解析、包安装、锁文件生成等核心流程,也不能拿到 PackageEvent 或 CommandEvent 这类带上下文的对象。
- 拼错事件名(比如写成
post-autoloader-dump)会静默失效,无任何提示 - PHP 回调必须是静态方法,且类需已注册到
autoload—— 否则报Class not found,但错误堆栈常被 Composer 吞掉 - 脚本失败默认中断后续流程,得加
@前缀忽略:"@phpstan analyse" -
composer install --no-scripts或 CI 缓存了vendor/,会导致post-install-cmd根本不触发
插件必须满足的硬性条件
Composer 只加载满足以下全部条件的包为插件:
-
composer.json中必须有"type": "composer-plugin" - 主类必须实现
Composer\Plugin\PluginInterface,且activate()方法签名严格为activate(Composer\Composer $composer, Composer\IO\IOInterface $io) - 类路径必须与
autoload["psr-4"]配置一致,命名空间不能错一级 - 不能在
activate()里做耗时操作(如远程请求、扫描目录),否则每次composer命令都卡顿
漏掉任意一条,composer show --plugins 就看不到你的插件,也不会调用任何逻辑。
监听 pre-update-cmd 和 post-install-cmd 的常见误区
这两个事件名最常用,但也最容易误用:
-
post-install-cmd只在首次composer install(无composer.lock时)触发;post-update-cmd才在composer update或composer install --with-dependencies时触发 - 事件名是字符串,不是常量:
'post-install-cmd'✅,ScriptEvents::POST_INSTALL_CMD❌(那是脚本事件常量,插件里不认) - 回调函数参数类型必须是
Composer\EventDispatcher\Event或其子类,写成ScriptEvent会导致运行时类型不匹配 - 想获取已安装包列表?别用
$composer->getPackage()->getRequires(),那是根包依赖;要用$composer->getRepositoryManager()->getLocalRepository()->getPackages()
调试插件是否生效的关键动作
别靠猜,直接验证:
- 运行
composer show --plugins,确认你的插件出现在列表里,且版本号对得上 - 加一句
$io->writeError('[DEBUG] onPostInstall triggered');到事件处理方法开头,看终端有没有输出 - 用
composer install -v或composer update -vvv查看详细日志,确认事件分发器是否调用了你的回调 - 在
activate()里故意 throw new RuntimeException('test'),如果没报错,说明插件根本没加载——回头检查type和自动加载配置
真正难的不是写逻辑,而是让 Composer 在正确时机、以正确方式把事件对象交到你手上;字段缺失、版本差异、异常未捕获,都可能让插件静默失效,而不是抛错告诉你哪里错了。


















