如何排查Composer post-install脚本执行失败的问题?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1126个文字,预计阅读时间需要5分钟。
markdownpost-install-cmd 脚本未执行,90% 是因为根本未注册成功,或执行时环境崩了——不是脚本逻辑错,是 Composer 基本没看到它,或者看到后立刻被 PHP 干掉了。
怎么确认 post-install-cmd 真被注册了
Composer 不会扫描文件、不自动发现脚本,只认 composer.json 根级 "scripts" 对象里明确写的 "post-install-cmd"(注意:不是 post-install,也不是 post-install-cmds)。常见失效点:
-
"scripts"块被错放在"autoload"或"require"里面,JSON 层级错误 → Composer 完全忽略 - 键名拼成
"postinstall-cmd"(少横线)或"postInstallCmd"(驼峰)→ 不匹配钩子名 - 值是字符串但没加引号,比如
php build.php写成php build.php(无双引号),JSON 解析失败 → 整个scripts段被丢弃 - 修改完没删
vendor/和composer.lock就重跑composer install→ Composer 可能跳过钩子(尤其之前已安装成功过)
脚本执行报错却只显示“Script failed”
默认输出会吞掉真实错误,你看到的只是壳命令退出码,不是 PHP 报错本身。必须用三级详细模式暴露底层 stderr:
- 运行
composer install -vvv(不是-v或-vv),它会打印出完整执行命令、环境变量,以及脚本进程的原始Fatal error、ParseError或Class not found - 如果输出里有
sh: php: not found或'php' is not recognized,说明 shell 找不到php命令 —— 不是脚本问题,是 PATH 缺失或 CLI PHP 未安装 - 若报错出现在
require 'vendor/autoload.php'阶段,大概率是脚本执行太早:post-install-cmd在autoload.php生成前就触发了,此时类加载器还不存在
脚本里 require 类或调用函数总失败
根本矛盾在于执行时机和自动加载器就绪状态不一致。常见场景和对策:
- 脚本内容是
php scripts/init.php,而init.php里用了new App\Configurator()→ 必须确保vendor/autoload.php已存在,否则直接Class not found - 解决方案一:把逻辑挪到
"post-autoload-dump"钩子下,它保证autoload.php已写入且可用 - 解决方案二:在脚本开头加防护判断:
if (!file_exists('vendor/autoload.php')) { echo "autoload missing\n"; exit(1); } - 路径别依赖当前目录:脚本中写
php ./scripts/build.php是安全的(.指项目根),但写php scripts/build.php在某些 CI 环境下可能因工作目录被覆盖而失败
脚本执行卡住或超时
不是代码死循环,而是外部依赖阻塞。典型表现是 composer install -vvv 卡在某条命令不动,几秒后报 process-timeout:
- Composer 默认
process-timeout是 300 秒,但某些操作(如生成大配置、扫描数百个 YAML 文件、连接慢数据库)会超时 - 临时延长:运行
composer config -g process-timeout 1200(单位秒),或项目内设composer config process-timeout 1200 - 检查是否调用了外部命令(如
git、zip、curl)而它们被代理/DNS/防火墙卡住 —— 在终端手动执行相同命令看是否响应 - 脚本里用了
sleep()、file_get_contents()或shell_exec()且目标不可达,也会静默卡住,-vvv日志里会显示该命令但无后续输出
最常被忽略的一点:很多脚本失败其实发生在 vendor/autoload.php 尚未生成的窗口期,而不是脚本本身有 bug。别急着改逻辑,先确认钩子注册正确、执行时机合理、PHP 环境可访问、路径不依赖隐式 cwd —— 这四点对了,80% 的“脚本不执行”问题就消失了。
本文共计1126个文字,预计阅读时间需要5分钟。
markdownpost-install-cmd 脚本未执行,90% 是因为根本未注册成功,或执行时环境崩了——不是脚本逻辑错,是 Composer 基本没看到它,或者看到后立刻被 PHP 干掉了。
怎么确认 post-install-cmd 真被注册了
Composer 不会扫描文件、不自动发现脚本,只认 composer.json 根级 "scripts" 对象里明确写的 "post-install-cmd"(注意:不是 post-install,也不是 post-install-cmds)。常见失效点:
-
"scripts"块被错放在"autoload"或"require"里面,JSON 层级错误 → Composer 完全忽略 - 键名拼成
"postinstall-cmd"(少横线)或"postInstallCmd"(驼峰)→ 不匹配钩子名 - 值是字符串但没加引号,比如
php build.php写成php build.php(无双引号),JSON 解析失败 → 整个scripts段被丢弃 - 修改完没删
vendor/和composer.lock就重跑composer install→ Composer 可能跳过钩子(尤其之前已安装成功过)
脚本执行报错却只显示“Script failed”
默认输出会吞掉真实错误,你看到的只是壳命令退出码,不是 PHP 报错本身。必须用三级详细模式暴露底层 stderr:
- 运行
composer install -vvv(不是-v或-vv),它会打印出完整执行命令、环境变量,以及脚本进程的原始Fatal error、ParseError或Class not found - 如果输出里有
sh: php: not found或'php' is not recognized,说明 shell 找不到php命令 —— 不是脚本问题,是 PATH 缺失或 CLI PHP 未安装 - 若报错出现在
require 'vendor/autoload.php'阶段,大概率是脚本执行太早:post-install-cmd在autoload.php生成前就触发了,此时类加载器还不存在
脚本里 require 类或调用函数总失败
根本矛盾在于执行时机和自动加载器就绪状态不一致。常见场景和对策:
- 脚本内容是
php scripts/init.php,而init.php里用了new App\Configurator()→ 必须确保vendor/autoload.php已存在,否则直接Class not found - 解决方案一:把逻辑挪到
"post-autoload-dump"钩子下,它保证autoload.php已写入且可用 - 解决方案二:在脚本开头加防护判断:
if (!file_exists('vendor/autoload.php')) { echo "autoload missing\n"; exit(1); } - 路径别依赖当前目录:脚本中写
php ./scripts/build.php是安全的(.指项目根),但写php scripts/build.php在某些 CI 环境下可能因工作目录被覆盖而失败
脚本执行卡住或超时
不是代码死循环,而是外部依赖阻塞。典型表现是 composer install -vvv 卡在某条命令不动,几秒后报 process-timeout:
- Composer 默认
process-timeout是 300 秒,但某些操作(如生成大配置、扫描数百个 YAML 文件、连接慢数据库)会超时 - 临时延长:运行
composer config -g process-timeout 1200(单位秒),或项目内设composer config process-timeout 1200 - 检查是否调用了外部命令(如
git、zip、curl)而它们被代理/DNS/防火墙卡住 —— 在终端手动执行相同命令看是否响应 - 脚本里用了
sleep()、file_get_contents()或shell_exec()且目标不可达,也会静默卡住,-vvv日志里会显示该命令但无后续输出
最常被忽略的一点:很多脚本失败其实发生在 vendor/autoload.php 尚未生成的窗口期,而不是脚本本身有 bug。别急着改逻辑,先确认钩子注册正确、执行时机合理、PHP 环境可访问、路径不依赖隐式 cwd —— 这四点对了,80% 的“脚本不执行”问题就消失了。

