Composer的scripts字段必须定义在composer.json根目录顶层,是命令别名与生命周期事件触发器的组合,支持显式调用(如composer run)和隐式事件(如post-install-cmd),仅四个事件适用于部署。

Composer 的 scripts 不是用来写业务逻辑的,而是让命令自动化、可复用、可传播——它本质是项目级的“快捷方式集合”,不是脚本语言。
scripts 字段写在哪?必须在 composer.json 顶层
很多人把 scripts 塞进 autoload 或 require 里,结果完全不生效。它必须和 name、require、autoload 并列,处于 composer.json 最外层对象中:
{
"name": "my/app",
"require": { ... },
"autoload": { ... },
"scripts": {
"dev:setup": "php artisan migrate --seed",
"prod:clear": [
"php artisan cache:clear",
"php artisan view:clear"
]
}
}
注意两点:
-
scripts是一个 JSON 对象,键是自定义命令名(如dev:setup),值可以是字符串(单条命令)或字符串数组(多条顺序执行) - 数组形式只在 Composer 2.2+ 支持;老版本(如 1.x)只认字符串,多条需用
&&拼接 - 所有命令都在项目根目录下执行,路径相对项目根,不是 vendor 或当前 shell 路径
哪些内置脚本钩子能自动触发?
Composer 会在特定生命周期自动运行匹配的 scripts 键,无需手动调用。最常用的是:
-
post-install-cmd:仅当首次运行composer install(且无composer.lock)时触发 -
post-update-cmd:每次composer update完成后触发,适合清缓存、重生成配置 -
post-autoload-dump:每次自动加载映射更新后触发(比如改了autoload或运行了composer dump-autoload),适合生成类映射文件或扫描注解
⚠️ 注意:post-install-cmd 在有 composer.lock 时不会触发(此时走的是 install 流程,不是“首次安装”),所以别指望它在 CI 部署时每次都跑数据库迁移——更稳妥的是显式调用自定义脚本,比如 composer run dev:setup。
怎么安全地调用 PHP 类方法?避免 autoload 未就绪
直接写 "App\Scripts\Build::generate" 看似简洁,但极易失败:此时 autoloader 可能还没加载完,composer install 过程中 vendor/autoload.php 尚未生成或未被引入。
正确做法是用 php 显式执行一个已知存在的入口脚本:
- 写一个
bin/build.php,开头手动 requirevendor/autoload.php - 在
scripts中调用"php bin/build.php" - 或者用 Composer 内置的
php命令 +-d参数强制加载(不推荐,太绕)
示例 bin/build.php:
<?php require __DIR__ . '/../vendor/autoload.php'; (new App\Scripts\Build())->generate();
为什么 run 命令比直接写 shell 更可靠?
从 Composer 2.2 开始,composer run <script-name></script-name> 成为标准方式。相比手动敲 php artisan ...,它的好处是:
- 自动继承项目定义的环境变量(如
COMPOSER_MEMORY_LIMIT) - 支持
--no-interaction和--quiet等通用参数透传 - 跨平台兼容性更好(Windows 下不用纠结
.batvs.sh) - 能被其他工具(如 Makefile、CI YAML)统一引用,不硬编码命令细节
但要注意:如果你的脚本依赖某个命令行工具(比如 mysql 或 redis-cli),run 不会帮你检查它是否存在——这得靠你自己在脚本里做 exec('which mysql') 或 try/catch 处理。
真正容易被忽略的点是:scripts 的执行上下文不等于你开发时的 CLI 环境。PATH、PHP ini 设置、扩展启用状态,都以当前运行 composer 命令的 PHP 解释器为准。调试时别只在 IDE 里跑,一定要在终端用 composer run xxx --verbose 看真实输出。


















