Composer 的 scripts 是事件驱动的钩子机制,需显式调用或由内置事件(如 post-install-cmd)触发,本质为命令注册表,支持字符串、数组、对象格式,含 description 说明,执行路径以项目根为准。

Composer 的 scripts 不是“运行一次就完事”的快捷命令,而是与生命周期深度绑定的钩子机制——它默认不自动执行,必须显式调用或被特定事件触发。
scripts 是什么:不是 shell 别名,而是事件驱动的钩子
composer.json 中的 scripts 字段定义的是可被 composer run 或 Composer 内置事件(如 post-install-cmd)触发的命令列表。它不等价于 Bash alias,也不支持直接写多行逻辑,本质是「命令注册表」。
- 每个键名是脚本名(如
dev-start),值可以是字符串(单条命令)、字符串数组(顺序执行)、或对象(带script和description) - Composer 会自动识别并响应标准事件名,例如
pre-autoload-dump、post-update-cmd,这些无需手动调用 - 自定义脚本名(如
build:api)必须用composer run build:api显式触发 - 脚本中引用环境变量需用
$COMPOSER_HOME等 Composer 提供的变量,不能直接用$PWD—— 因为执行路径可能被切换
如何定义一个带参数和描述的脚本
脚本支持内联参数传递(通过 -- 分隔),但仅限于 CLI 模式下手动运行;事件触发时无法传参。推荐用 description 字段说明用途,方便团队协作。
{
"scripts": {
"test:unit": {
"script": "vendor/bin/phpunit --colors=always",
"description": "Run unit tests with color output"
},
"lint:php": "php -l src/*.php"
}
}
- 使用对象格式可添加
description,运行composer list时会显示该说明 - 字符串数组形式支持跨平台兼容写法:
["@composer install", "npm ci"],其中@composer表示当前 Composer 二进制路径 - 避免在脚本里写
cd xxx && command,改用--working-dir参数或在命令中指定路径,比如phpunit --configuration tests/phpunit.xml tests/
常见错误:脚本不执行、路径错乱、权限失败
最常遇到的不是语法错误,而是执行上下文误解:
-
“我写了 post-install-cmd 却没反应”:确认是否刚执行过
composer install(而非update);install只在首次生成vendor时触发,后续install若无变更则跳过事件 -
“脚本里找不到 vendor/bin/xxx”:因为
post-install-cmd触发时vendor尚未完全写入完成,应改用post-autoload-dump或确保命令在vendor存在后再执行 -
“Windows 下 npm 命令报错”:不要写
npm run build,改用node_modules/.bin/npm run build或启用bin-dir并加vendor/bin到 PATH -
脚本中调用 PHP 文件却提示 “No such file”:Composer 默认以项目根目录为工作路径,但某些 IDE 或 CI 环境会覆盖
CWD,建议所有路径用相对项目根的写法,如php scripts/deploy.php
进阶技巧:组合事件 + 自定义脚本复用
可以把常用逻辑封装成独立脚本文件,再在 scripts 中调用,提升可维护性:
{
"scripts": {
"ci:setup": [
"@composer install --no-interaction --prefer-dist",
"php scripts/check-cs.php",
"php scripts/generate-api-docs.php"
],
"post-autoload-dump": ["php scripts/post-autoload.php"]
}
}
- 把复杂逻辑抽离到
scripts/目录下的 PHP 文件,比长字符串更易调试、测试和版本管理 -
post-autoload-dump是少数能稳定保证vendor/autoload.php已生成且可用的事件,适合做类映射检查、动态配置生成等操作 - CI 场景下慎用
pre-install-cmd:它会在依赖解析前执行,此时vendor还不存在,连autoload.php都不可用
真正容易被忽略的点在于:Composer 脚本的执行时机和上下文是隐式的,不是“写完就能跑”。尤其当多个事件嵌套(比如 post-update-cmd 内又调用了 composer run xxx),会触发二次加载,可能引发 autoload 冲突或路径漂移。动手前先用 composer run -v xxx 看完整执行链路,比猜更可靠。










