post-install-cmd 默认失败中断安装是因为 Composer 将其视为关键构建步骤,非0退出码会终止流程;解决方法是确保脚本最终返回0,如末尾加 exit(0)、用 sh -c 'cmd || true' 包裹或通过插件拦截。
Composer 的 post-install-cmd 脚本出错时,默认会中断整个安装流程,但很多团队其实只希望它“尽力而为”——比如生成缓存、触发通知、检查配置,失败了也不该让 composer install 报错退出。
因为 Composer 将其视为“构建生命周期关键步骤”,只要脚本返回非 0 状态码(例如 PHP 脚本中 exit(1)、shell 命令执行失败),就会终止后续操作并报错:Script xxx handling the post-install-cmd event returned with error code 1。
这不是 bug,是设计行为。但实际中,你往往只需要“记录+忽略”,而非“阻断”。
核心思路:确保脚本最终返回状态码 0,同时保留错误可见性。
exit(0),哪怕前面有异常或 trigger_error();scripts 中用 shell 包裹命令,强制返回 0:"post-install-cmd": ["sh -c 'php bin/check-config.php || true'"]
hirak/prestissimo 不适用,但可自写)拦截事件并吞掉异常——不过多数场景没必要,过度复杂。别依赖 try/catch 就完事。Composer 执行的是 CLI 脚本,未捕获的致命错误(Fatal error)、语法错误、扩展缺失都会直接退出并返回非 0 状态。
推荐结构:
getMessage()); } // 关键:无论成败,都 exit(0) exit(0);
注意:register_shutdown_function 能兜住 parse/fatal 错误,但无法恢复执行;try/catch 处理运行时异常;最后的 exit(0) 是底线。
脚本失败并中断?不是所有脚本都该“静默”。以下场景应保持失败传播:
php artisan key:generate)失败 —— 应用将无法启动;php artisan migrate:status --dry-run)发现不兼容变更;composer.lock 对应的 SIGNATURE)失败,涉及安全可信链。判断标准很简单:如果该步骤的结果是后续命令/应用启动的**必要前提**,就别吞错误。
真正容易被忽略的点是:很多人改了脚本返回值,却忘了 CI/CD 流水线里还用 set -e 或类似机制捕获所有命令退出码——这时候即使 PHP 脚本 exit(0),外层 shell 仍可能因 || 写法或管道错误中断。得通盘看执行上下文。
# 报错
# 解决方法
# php
# 数据库
# 的是
# 将其
# 就会
# 是因为
# 很多人
# 三种
# 很简单
# 这不是
# catch
# Event
# composer
# 事件
# 为什么
# Error
# 状态码
# bug
# try
# 尽力而为