自定义 Composer Installer 需严格满足契约:type 必须为 "composer-plugin",extra.class 指向实现 PluginInterface 的类,并在 activate() 中注册 Installer;supports() 必须精确匹配 package type,getInstallPath() 返回干净相对路径,install()/update() 必须用 Composer 工具类操作文件。

自定义 Composer Installer 不是加个配置就能生效的魔法开关,它是一套必须严格满足契约的注册机制——漏掉任何一个接口、路径或类型声明,你的代码就等于没写。
composer.json 里 type 和 extra.class 必须同时配对
插件包自身的 composer.json 中,"type" 必须是 "composer-plugin",不是 "library" 或 "composer-installer";否则 Composer 根本不会加载它。
extra.class 的值必须是完整命名空间类名(比如 "Acme\Installer\Plugin"),且该类必须可被 PSR-4 自动加载。常见错误包括:
- 类名拼错或命名空间没在
autoload里声明 -
extra.class指向了 Plugin 类,但 Plugin 类没实现Composer\Plugin\PluginInterface - Plugin 类实现了接口,但没在
activate()方法里调用$installerManager->addInstaller($yourInstaller)
运行 composer diagnose 查看 “Plugins” 列表,你的插件不在里面?说明它根本没被载入。
supports() 返回 false 就彻底不触发
Composer 在 install/update 阶段遍历所有已注册的 Installer 实例,对每个包调用其 supports() 方法。只有返回 true 的那个 Installer 才会进入后续流程;其他全被跳过,连 getInstallPath() 都不会执行。
这个方法必须精确匹配 $package->getType():
- 正确:
return $package->getType() === 'my-framework-bundle'; - 错误:
strpos($package->getType(), 'my-') !== false—— Composer 不做模糊匹配 - 错误:
$package->getPrettyName() === 'acme/my-bundle'—— type 字段才是唯一判断依据
调试时可在 supports() 里加 $io->write("Checking type: " . $package->getType());,配合 composer install -v 看是否被调用。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
getInstallPath() 必须返回干净的相对路径
getInstallPath() 的返回值会被拼接到 vendor/ 目录下,最终形成完整安装路径。它不是目标绝对路径,也不是项目根目录下的相对路径。
必须满足:
- 返回值不含
..或/开头(如../app/bundles或/app/bundles会直接抛InvalidArgumentException) - 路径结尾不强制加
/,但建议加,避免和文件名冲突 - 别指望
{$name}这类变量自动替换——那是composer/installers的语法,你得手动拼字符串:return 'app/bundles/' . $package->getPrettyName();
这个方法只声明路径,不创建目录、不复制文件;这些动作得在 install() 里用 $filesystem->copy() 显式处理。
install() 和 update() 必须用 Composer 提供的工具类操作文件
手写 mkdir + copy 是翻车高发区:Windows 路径分隔符、权限问题、符号链接、相对路径解析错位……全在这儿爆雷。
正确做法是复用 Composer 自带的工具类:
- 用
$filesystem->ensureDirectoryExists($targetDir)替代mkdir -p - 复制文件用
$filesystem->copy($source, $target, true)(第三个参数启用覆盖) - 获取目标路径时,从
$config->get('vendor-dir')出发,别硬编码./vendor - 日志输出必须走
$io->writeError(""),否则在 quiet 模式下看不到任何提示
最容易被忽略的是:你的 Installer 类必须实现 Composer\Installer\InstallerInterface,且至少提供 supports() 和 install();缺了接口,Composer 就当它不存在。

















