post-update-cmd 是 composer 在 composer update 或 composer install 导致 composer.lock 实际更新后,且在 composer.json 的 scripts 中明确定义时才执行的命令;它不保证每次 install 都运行,失败会导致整个命令退出。

post-update-cmd 是什么,它在什么时候执行
它不是“更新后自动运行的万能钩子”,而是 composer update 或 composer install(当锁文件被更新时)成功完成、且 composer.json 中明确配置了该字段后,才执行的一段命令。它不运行于每次 composer install,只在依赖版本实际变动(即 composer.lock 被重写)时触发。
常见错误现象:post-update-cmd 完全没反应,其实是因为你只跑了 composer install 但 lock 文件没变;或者配置写在了错误位置(比如放在 config 下而非 scripts 下)。
- 必须放在
composer.json的"scripts"对象里 - 命令本身可以是 PHP 函数调用(如
"MyClass::doSomething"),也可以是 shell 命令(如"php artisan optimize:clear") - 如果命令失败(exit code ≠ 0),整个 Composer 命令会报错退出——这点常被忽略,导致 CI 环境卡住
怎么写一个安全可用的 post-update-cmd 脚本
别直接写一堆 shell 命令拼接,优先用可测试、有上下文的 PHP 方法。Composer 会自动加载 autoload,并传入 $event 对象(ComposerScriptEvent 实例),你能从中拿到 IO、composer 实例、当前操作类型等信息。
示例:清 Laravel 缓存并检查配置语法
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
"scripts": {
"post-update-cmd": [
"App\ComposerScripts::clearCaches",
"php -l app/Http/Controllers/HomeController.php"
]
}
- PHP 方法必须是
public static,且接受单个$event参数 - shell 命令中不要依赖未声明的环境变量(如
$PATH在 CI 中可能极简),建议用绝对路径或先检测which php - 避免在脚本里做耗时操作(如下载资源、跑全量测试),它会拖慢本地开发流程
为什么 post-update-cmd 有时不执行,有时执行两次
根本原因在于 Composer 的“事件传播机制”:父项目定义的 post-update-cmd 不会自动继承给依赖包;但如果你在某个包里也写了同名脚本,而它又被设为 "type": "library"(默认),那它的脚本根本不会被触发——只有 "type": "project" 或显式启用 composer-plugin 的包才可能干预主流程。
更常见的双触发场景:你在根项目写了脚本,又用了 Laravel 的 laravel/framework,它内部注册了 post-autoload-dump,但这个和 post-update-cmd 是两回事;有人误把两者日志混在一起,以为重复了。
- 用
composer run-script --list确认哪些脚本实际被识别 - 加调试语句:在 PHP 方法开头写
file_put_contents('/tmp/post-update.log', date('c') . " ", FILE_APPEND); - CI 环境下注意
--no-interaction和--prefer-dist可能跳过某些生命周期阶段
替代方案:什么情况下不该用 post-update-cmd
当你需要确保某件事“一定发生”,且与依赖变更无强关联时,post-update-cmd 就不合适。比如生成 API 文档、提交代码规范检查结果、推送构建产物——这些属于构建流水线职责,应该交给 Makefile、GitHub Actions 或 npm script 管理。
另一个典型误用:用它来“修复”自动加载问题。实际上,composer dump-autoload 已在 post-update-cmd 之前完成,再手动调用一次只是浪费时间,还可能因并发写 autoload 文件引发警告。
- 想在每次
composer install都运行?用post-install-cmd,但它也不保证“每次”——只有 lock 文件存在且未改动时,install会跳过依赖解析,脚本照常执行 - 想监听特定包升级?
post-update-cmd拿不到“哪个包变了”,得自己比对composer.lock新旧版本 - 跨平台兼容性差的命令(如
del /q或rm -rf)尽量封装成 PHP 方法,避免 Windows 下直接失败










