直接在 Composer 的 scripts 字段定义命令即可注册自定义命令,支持字符串或数组语法,需注意执行路径、环境变量传递及退出码;支持全局钩子与手动触发,参数传递需借助 $@ 或封装 PHP 脚本处理,常见问题包括路径错误、command not found 和 autoload 失败。

直接写 scripts 字段就能注册自定义命令,不需要插件或额外依赖——但必须注意命令执行路径、环境变量和退出码是否被正确传递。
scripts 字段的语法和基本写法
Composer 的 scripts 是一个 JSON 对象,键是命令名(如 dev:clear),值是 shell 命令字符串或数组。它支持两种执行模式:全局钩子(如 post-install-cmd)和手动触发命令(如 composer dev:clear)。
- 单条命令直接写字符串:
"dev:clear": "php artisan cache:clear && php artisan view:clear" - 多条命令推荐用数组形式(更清晰,且避免 shell 解析差异):
["php artisan cache:clear", "php artisan view:clear"]
- 命令中可使用
$COMPOSER_BIN_DIR、$COMPOSER_HOME等内置环境变量,但不要依赖$PWD—— 实际工作目录可能是项目根目录,也可能是调用者所在路径
如何让自定义命令支持参数传递
Composer 本身不解析脚本参数,composer run-script xxx -- arg1 arg2 中的 -- 后内容会以 $@ 形式透传给 shell,但仅限于 shell 脚本或可执行文件;PHP 命令需自行处理 $argv。
- 纯 shell 场景(如调用 bash 脚本):
"deploy:to": "bash deploy.sh $@",然后运行composer run-script deploy:to -- staging - PHP 命令需显式接收:
"test:group": "php vendor/bin/phpunit --group $1",但注意$1在 Windows cmd 下不可用,建议统一用bash -c 'php ... $1'或改用封装脚本 - 更可靠的做法是写一个独立的 PHP 脚本(如
scripts/run-test.php),在scripts中调用它:"test:group": "php scripts/run-test.php",再由 PHP 解析$argv
常见错误:命令不执行、报错或路径不对
多数问题源于 Composer 执行脚本时的上下文与手动执行不一致,尤其是相对路径和命令查找逻辑。
-
command not found:默认不加载$PATH中的本地 bin(如vendor/bin/xxx),应显式写全路径或用php vendor/bin/xxx - “找不到类”或“autoload 失败”:确保脚本在
autoload-dev中已声明,或先执行composer dump-autoload - 权限问题(Linux/macOS):脚本文件需有执行权限(
chmod +x),否则sh: ./xxx.sh: Permission denied - Windows 下换行符或反斜杠问题:避免硬编码
\,优先用/或 PHP 的DIRECTORY_SEPARATOR
钩子脚本(如 post-update-cmd)的执行时机和限制
钩子不是“事件监听器”,而是固定阶段的同步阻塞调用,失败会导致整个 Composer 操作中断。
- 典型钩子:
pre-install-cmd、post-update-cmd、post-autoload-dump - 钩子中不能交互(
readline()或STDIN读取会卡住),也不能依赖未安装完成的包(post-install-cmd时 autoload 尚未生成) - 若需异步或复杂逻辑,建议把主逻辑抽到独立脚本,钩子只做轻量触发:
"post-autoload-dump": ["@php scripts/generate-config.php"]
- 钩子默认继承当前命令的选项(如
--no-dev),但无法区分是install还是update触发的同一个钩子
真正容易被忽略的是:scripts 中的命令默认在项目根目录执行,但如果你在子目录里运行 composer run-script,它仍会跳回根目录——这个行为没法关闭,也不受 COMPOSER_HOME 影响。










