Composer脚本需正确配置PHP CLI环境、置于composer.json顶层scripts字段且语法合法,否则会报错或静默失败;脚本名仅支持字母数字下划线短横线,避免覆盖内置命令。

Composer 脚本不是“写完就能跑”的 shell 命令,它依赖于 PHP CLI 环境、正确的路径解析和明确的触发时机。没配好运行环境,composer hello 就会报 Command "hello" is not defined 或静默失败。
scripts 字段必须放在 composer.json 顶层,且文件语法要合法
脚本定义错位置,Composer 根本不会加载它。常见错误是把 scripts 嵌套在 extra、config 或其他字段里,或者漏掉逗号导致 JSON 解析失败。
-
composer.json必须是有效的 JSON:用composer validate检查,它会直接告诉你哪一行缺引号或逗号 -
scripts是根级字段,和require、autoload并列,不能缩进到其他对象内部 - 值可以是字符串(单条命令)、字符串数组(顺序执行),但不能是关联数组(除非用
composer run的新语法) - 示例正确写法:
"scripts": { "hello": "echo 'Hello from Composer!'", "greet": ["php scripts/greet.php"] }
脚本里的 PHP 命令调用的是系统默认 php,不是你期望的那个
你在终端能 php -v 看到 PHP 8.2,但 composer run greet 却报 ParseError: syntax error, unexpected token "[",大概率是因为脚本里 php 调用的是系统自带的 PHP 7.2(比如 CentOS 7 的 /usr/bin/php)。
- 检查真实调用链:
head -n1 /usr/local/bin/composer应该是#!/usr/bin/env php,它依赖$PATH中第一个php - 验证当前脚本实际用的 PHP:
composer run --no-scripts --dry-run greet不会执行,但会打印出完整命令行,看它调用的是哪个php - 稳妥做法:脚本里显式写全路径,比如
"/usr/bin/php82 scripts/greet.php",或用php -d memory_limit=-1避免 CLI 配置干扰
生命周期事件(如 post-install-cmd)不会自动触发,除非满足条件
很多人以为只要写了 "post-install-cmd": ["echo 'done'"],每次 composer install 就一定执行——其实不然。这个事件只在 install 成功完成、且没有加 --no-scripts 时才触发。
-
composer install --no-scripts:跳过所有脚本,包括生命周期事件 -
composer install --no-autoloader:也会抑制部分事件(如post-autoload-dump),但不影响post-install-cmd - CI/CD 部署时常用
--no-interaction --no-dev --optimize-autoloader,但别漏掉--no-scripts—— 否则开发期写的post-install-cmd可能在生产环境意外执行数据库迁移 - 想手动测试事件是否生效?用
composer run-script post-install-cmd,这是最可控的方式
自定义脚本名不能带空格或特殊字符,且需避免和内置命令冲突
composer deploy:prod 看起来很清晰,但 Composer 默认不支持冒号分隔的命名;composer test:unit 会直接报错 Command "test:unit" is not defined。
- 合法脚本名只能含字母、数字、下划线、短横线(
a-z、0-9、_、-),不能以数字开头 - 不要覆盖内置命令:比如定义
"update"会覆盖原composer update,导致无法更新依赖 - 推荐命名风格:
deploy-prod、clear-cache、run-tests,然后用composer run deploy-prod显式调用 - 如果真想用嵌套式命名(如
deploy:prod),必须配合composer run+--no-scripts组合,并确保 Composer 版本 ≥ 2.5(旧版不支持)
最容易被忽略的一点:脚本执行时的当前工作目录是 composer.json 所在目录,但它的父进程环境(比如用户权限、umask、PATH)可能和你的登录 shell 不一致——尤其在 systemd 服务或 Jenkins agent 下跑 composer install 时,chmod 或 php artisan 很可能因权限或路径缺失而静默失败。别假设“本地能跑,线上就一定行”。











