post-install-cmd并非每次composer install都执行,仅当vendor/为空且composer.lock不存在或过期时触发;更稳定的选择是post-autoload-dump,它在每次生成autoload.php后必运行。

composer.json 里写 post-install-cmd 就能自动执行脚本?
不一定。只有当 composer install 真正执行了「安装新包」(而非仅从 vendor 目录复用已有代码)时,post-install-cmd 才会触发。如果 vendor/ 已存在且 composer.lock 未变,Composer 会跳过依赖解析和下载,直接解包 —— 此时该钩子根本不会运行。
更可靠的做法是统一使用 post-autoload-dump:它在每次生成或更新 vendor/autoload.php 后必执行,覆盖 install、update、甚至 dump-autoload 命令。
- 适合做代码生成、配置注入、静态分析入口等「只要 autoloader 变了就得跑」的事
- 避免误判「是否真安装了」,逻辑更稳定
- 注意:它不保证依赖已完全就位(比如某些插件可能还没被加载),别在其中调用尚未 autoload 的类
自定义事件处理器必须是静态方法吗?
不是必须,但强烈建议。Composer 的事件调度器通过反射调用处理器,要求目标可被无参调用。如果你写实例方法,得额外传入对象实例,而 Composer 不支持这种绑定方式。
正确写法是声明为 public static 方法,并在 composer.json 中按 "MyClass::myHandler" 格式引用:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
{
"scripts": {
"post-autoload-dump": [
"MyClass::myHandler"
]
}
}
- 非静态方法会报错:
Call to undefined method MyClass::myHandler()(即使方法存在) - 闭包、匿名函数无法被 Composer 序列化和持久化,不支持
- 如果需要访问实例状态(如读取配置),应在方法内自行 new 实例或用单例,别指望 Composer 帮你维护上下文
脚本执行失败会导致 composer install 中断吗?
默认会。任何脚本返回非零退出码(例如 PHP exit(1) 或抛出未捕获异常),Composer 都会终止后续流程,并向上返回错误。
这在 CI/CD 中很关键:你想让构建失败来暴露问题,但也得小心误伤。比如检查代码风格的脚本,若只是提示而非阻断,应显式返回 0:
public static function checkStyle()
{
$result = shell_exec('php-cs-fixer fix --dry-run --format=json src/');
if (strpos($result, '"changed":true') !== false) {
echo "⚠️ Style issues found, but continuing...\n";
return 0; // 别让 Composer 当成错误
}
return 0;
}
- PHP 脚本中未设
exit()时,默认返回 0;显式exit(0)或return 0更清晰 - Shell 命令需注意:管道、重定向可能掩盖真实退出码,建议用
$? == 0显式判断 -
composer install --no-scripts可临时跳过所有钩子,调试时有用
为什么 post-update-cmd 拿不到刚更新的包的新版本号?
因为 post-update-cmd 触发时,composer.lock 已写入磁盘,但 vendor 目录下的文件可能还在解压或软链接中 —— 尤其是用 symfony/flex 这类插件时,部分操作延后到 post-autoload-dump 才真正完成。
想安全获取某包当前生效的版本,别读 composer.lock 文件,改用 Composer 自带的 API:
$composer = \Composer\Factory::create(new \Composer\IO\NullIO());
$package = $composer->getRepositoryManager()->getLocalRepository()->findPackage('monolog/monolog', '*');
echo $package->getVersion(); // → 2.10.0
- 直接解析
composer.lock容易因 JSON 解析失败或结构变更挂掉 - 依赖
composer/composer包本身,生产环境一般不装,只应在 dev-only 脚本中用 - 最稳妥的时机其实是
post-autoload-dump+ 检查vendor/composer/installed.json,它才是 vendor 状态的最终快照
post-update-cmd 里急着读新版代码,结果读到的是旧缓存或半成品目录。










