Composer 的 scripts 是命令别名与执行时机控制,非钩子;自动执行需用 post-install-cmd 等事件,而非自定义 shell 脚本。

Composer 的 scripts 不是钩子(hooks),它只是命令别名 + 执行时机控制;想实现“安装后自动执行某操作”,得靠 post-install-cmd 这类事件,而不是自己写个 shell 脚本扔进去就完事。
哪些 event 名字能真正触发自动执行
Composer 只在特定生命周期事件发生时调用 scripts,不是所有名字都有效。常见且稳定可用的有:
-
pre-install-cmd:运行composer install前 -
post-install-cmd:composer install成功后(含首次安装) -
pre-update-cmd:运行composer update前 -
post-update-cmd:composer update成功后 -
post-autoload-dump:每次自动生成 autoload 文件后(比如增删包、改autoload配置)
注意:post-root-package-install 和 post-create-project-cmd 只在 create-project 场景下触发,普通 install/update 不会跑。
脚本内容写成 PHP 函数还是 shell 命令
两种写法都能用,但行为差异很大:
- 写成字符串如
"php build.php":走系统 shell 执行,路径基于当前工作目录,环境变量继承终端会话 - 写成数组如
["MyScript::build"]:由 Composer 加载并调用静态方法,MyScript必须可 autoload,且不能依赖未安装完成的依赖(post-install-cmd时 vendor 可能还没完全就绪)
推荐优先用 shell 命令形式,更可控。例如:
"scripts": {
"post-install-cmd": [
"php artisan clear-compiled",
"php artisan optimize:clear"
]
}
如果要用 PHP 类,确保类文件在 autoload/files 或已声明命名空间,并在 post-autoload-dump 后再调用。
为什么 post-install-cmd 有时不执行
这不是 bug,而是 Composer 的优化机制在起作用:
- 运行
composer install --no-scripts会跳过全部 scripts - 如果
vendor/autoload.php已存在且composer.lock没变,Composer 可能直接跳过 install 流程,也就不会触发post-install-cmd - 脚本中用了
exit()或抛出未捕获异常,会导致后续 script 中断,且 Composer 不会报错提示 - Windows 下用双引号包裹命令时,反斜杠或空格容易被 cmd 解析错,建议统一用单引号或改用 cross-env
调试技巧:加一句 "echo 'running post-install-cmd'" 到开头,确认是否真没进。
scripts 和插件(plugin)的本质区别
scripts 是用户层的快捷命令封装,没有权限干涉 Composer 内部流程;而 plugin 是通过 composer-plugin-api 注册监听器,能 hook 到更底层事件(如包下载前、包解压后)。如果你需要:
- 修改包安装路径
- 动态生成配置文件并注入 autoload
- 拦截并重写某个包的源地址
那 scripts 做不到,必须写 plugin。但 90% 的“自动执行”需求,post-autoload-dump + 简单 shell 就够了——别一上来就想造轮子。
最常被忽略的一点:scripts 的执行顺序是按数组顺序来的,但每个 script 是独立进程;如果两个 script 都写成 php foo.php,它们之间不共享内存或变量,也看不到彼此 stdout。要传数据,得靠文件或环境变量。










