Composer scripts需显式调用或通过生命周期命令触发,非自动运行;键名分内置钩子(如post-install-cmd)和自定义命令,执行受--no-scripts、路径、权限、环境及递归调用影响。

scripts 里写的命令到底怎么执行
Composer 的 scripts 不是自动运行的,它只是注册了一组命名命令,必须显式调用才能触发。很多人写完 "post-install-cmd": "php build.php" 就以为装包时会自动跑,结果啥也没发生——因为默认不启用钩子执行,得加 --no-scripts 才会跳过,而默认其实是「允许」,但前提是:你得真去运行 composer install 或 composer update 这类会触发生命周期的命令。
实操建议:
- 想手动执行某个 script,用
composer run-script <script-name></script-name>,比如composer run-script post-install-cmd - 想让
install自动触发post-install-cmd,确保没加--no-scripts参数(CI 环境有时会默认加) - 脚本值如果是字符串,会被 shell 解析;如果是数组,会逐条执行(顺序敏感)
- 路径问题很常见:脚本里用的相对路径,是以项目根目录(即
composer.json所在位置)为基准,不是以当前 shell 工作目录为准
PHP 函数和 CLI 命令混写容易崩在哪
在 scripts 里直接写 "build": "php -r \"echo date();\"" 看似没问题,但引号嵌套、环境变量、输出重定向全会变脆弱。更典型的是误把 PHP 函数当命令用,比如写 "test": "var_dump(1)" —— 这根本不是 shell 命令,会报 sh: var_dump: not found。
实操建议:
- 纯 PHP 逻辑,优先写成独立文件 +
php path/to/script.php,别塞内联代码 - 需要传参?用
$argv接收,不要依赖$_SERVER['argv'],因为 composer run-script 会把 script 名也塞进参数里 - 想调用自定义类或 Composer 自动加载?确保脚本文件顶部有
require __DIR__ . '/vendor/autoload.php'; - Windows 下反斜杠、空格路径、PowerShell 和 cmd 行为差异大,测试务必在目标环境跑
scripts 键名不是随便起的,有些名字有特殊含义
Composer 识别一部分固定名称作为生命周期钩子,比如 pre-install-cmd、post-autoload-dump,它们会在特定时机自动执行;而像 build、lint 这种自定义名,只能靠 composer run-script build 显式调用。混淆这两类会导致“为什么我写了 pre-update-cmd 却没反应”——可能是因为你只跑了 composer install,而它只触发 install 相关钩子。
实操建议:
- 查官方文档确认钩子触发时机,常用钩子包括:
pre-install-cmd、post-install-cmd、pre-update-cmd、post-update-cmd、post-autoload-dump - 自定义命令名避免和内置钩子重名,否则行为可能被覆盖或叠加
- 钩子脚本失败(exit code ≠ 0)会导致整个 composer 命令中断,默认行为,不可跳过
- 调试钩子是否触发?加一句
echo "RUNNING post-install-cmd"到脚本开头,最直白
script 中调用其他 composer 命令要小心递归和上下文
在 post-install-cmd 里再写 composer dump-autoload 是常见操作,但要注意:这会重新读取 composer.json 并再次触发钩子——如果 dump-autoload 又触发了 post-autoload-dump,而后者又调用了别的 composer 命令……就可能形成隐式递归,尤其在 CI 上容易卡死或超时。
实操建议:
- 避免在钩子里调用会再次触发同类钩子的命令,比如
composer install在post-install-cmd里就是危险操作 - 需要用
composer命令时,加--no-scripts抑制二次触发,例如:composer dump-autoload --no-scripts - 钩子执行时的当前工作目录是项目根目录,但
COMPOSER_HOME、COMPOSER_VENDOR_DIR等环境变量未必是你预期的值,别假设它们一定存在 - 权限问题常被忽略:某些脚本生成文件后,后续命令因权限不足读不到,比如
phpunit找不到缓存目录
scripts 里,而取决于你用什么命令触发、有没有禁用钩子、路径和权限是否匹配。最容易被忽略的是:钩子失败会中断整个流程,而错误输出可能被 composer 的进度条吞掉,得加 -v 或重定向看真实 exit code。










