Composer如何设置自定义脚本钩子?(事件监听示例)

7次阅读

scripts 必须作为 composer.json 顶层字段,键为 composer 内置事件名(如 post-install-cmd),值支持字符串、数组或 classname::methodname 格式;事件名拼写错误或位置错误将导致静默失效。

Composer如何设置自定义脚本钩子?(事件监听示例)

composer.json 里怎么写 scripts 字段

Composer 的脚本钩子全靠 scripts 字段驱动,它不是插件也不是扩展,就是个 JSON 键值对。写错位置或格式,composer install 不报错但脚本压根不触发。

  • scripts 必须是顶层字段,和 requireautoload 平级,不能塞进 configextra
  • 键名是事件名(比如 post-install-cmd),值可以是字符串命令、数组命令、或指向 PHP 方法的 ClassName::methodName
  • 如果值是数组,Composer 会按顺序执行每一项;字符串则直接交给 shell 解析,注意引号和空格转义

示例:在项目根目录 composer.json 中添加

"scripts": {   "post-install-cmd": [     "echo '安装完成'",     "php -r "file_put_contents('runtime/installed', date('c'));""   ],   "pre-autoload-dump": "MyScript::beforeAutoload" }

哪些事件名真正可用、什么时候触发

事件名不是随便写的,必须是 Composer 内置的生命周期钩子,拼错一个字母就静默失效。常见误区是把 post-update 当成合法事件——实际只有 post-update-cmd

  • 命令类事件带 -cmd 后缀:pre-install-cmdpost-update-cmdpost-autoload-dump(无 -cmd
  • post-autoload-dump 在生成自动加载文件后触发,适合清理旧缓存或生成代理类;post-install-cmdpost-update-cmd 区别在于前者只在首次 install 触发,后者在 updateinstall(有 lock 文件时)都触发
  • 自定义脚本名(如 build:assets)不会自动绑定事件,需手动运行 composer run build:assets,也不能被其他事件监听

PHP 类方法当脚本时要注意什么

ClassName::methodName 形式调用 PHP 方法看似高级,但容易因自动加载失败而中断——Composer 运行脚本时,vendor/autoload.php 尚未完全就绪,尤其是 pre-autoload-dump 阶段。

  • 方法必须是 public Static,且参数签名要匹配:通常接收一个 ComposerScriptEvent 实例
  • 不要在方法里依赖尚未生成的 autoload 文件,比如别在 pre-autoload-dump 里 new 一个刚 require 的类
  • 调试时加 var_dump(get_class($event)); exit; 看是否真进了方法,比猜日志更直接

示例类写法:

class MyScript {     public static function beforeAutoload($event)     {         $vendorDir = $event->getComposer()->getConfig()->get('vendor-dir');         file_put_contents("$vendorDir/../.build-timestamp", time());     } }

脚本执行失败却不报错?检查这几点

默认情况下,脚本返回非零退出码,Composer 只会警告(Script xxx handling the xxx event returned with Error code 1),但不会中断后续流程——除非你加了 --no-interaction 或设了 COMPOSER_NO_INTERACTION=1

  • composer run-script post-install-cmd -v-v 查看完整输出,隐藏的 permission denied 或 command not found 就会露出来
  • Shell 命令中含管道、重定向或 && 时,整个表达式被视为单个命令,出错不会被单独捕获;建议拆成多个数组项,或用 sh -c "xxx && yyy" 包一层
  • windowsphp -r 的双引号容易和 CMD 解析冲突,改用单引号包裹 PHP 代码,或直接写 .php 文件再调用

最常被忽略的是:脚本在 CI 环境里以 nobody 用户运行,对 storage/runtime/ 目录没写权限,但错误被吞掉,只看到时间戳没更新。

text=ZqhQzanResources