cli下set_error_handler看似无效,是因为php默认开启display_errors=1,错误直接输出终端;handler需返回true才能屏蔽原生输出,且http_response_code()在cli中无效。

CLI下set_error_handler为什么看起来没生效
因为 CLI 默认开启 display_errors = 1,错误一发生就直接打到终端,你写的 set_error_handler 虽然注册成功,但 PHP 仍会走默认逻辑输出——除非你在 handler 函数里返回 true 显式屏蔽它。
更关键的是:CLI 不会自动改 HTTP 状态码(压根没 HTTP),所以别在 handler 里调 http_response_code(),纯属无效操作。
- 必须在脚本最顶部(甚至早于
require框架文件)调用set_error_handler() - handler 函数末尾务必
return true,否则原生错误仍会刷屏 - CLI 下
error_reporting()仍起作用,建议设为E_ALL & ~E_DEPRECATED避免干扰 - 若用
pcntl_fork()或子进程,每个进程需单独注册 handler
怎么把错误转成异常再统一处理
PHP 7+ 的 TypeError、ParseError 等本质是异常,不进 set_error_handler,只走 set_exception_handler。想统一兜底,就得在 error handler 里主动 throw。
典型做法是:在 set_error_handler 回调中,对非 E_NOTICE/E_USER_DEPRECATED 的错误,全部包装成 ErrorException 抛出,让 set_exception_handler 一并接管。
function handleError($level, $message, $file, $line) {
if (!(error_reporting() & $level)) return false;
if ($level === E_NOTICE || $level === E_USER_DEPRECATED) {
// 仅记录,不中断
error_log("[$level] $message in $file:$line");
return true;
}
throw new ErrorException($message, 0, $level, $file, $line);
}
- 注意过滤
@抑制的错误:if (error_reporting() === 0) return false; - 不要在 handler 里再调
trigger_error(),容易递归崩溃 -
ErrorException构造时传入$level,后续可在异常处理器里做分级响应
CLI专用错误格式化:用 PlainTextHandler 避免堆栈刷屏
原生异常堆栈在终端里全是缩进和颜色乱码,whoops 的 PlainTextHandler 就是为此设计的——它不依赖 HTML 渲染,专吃 CLI 和日志。
安装后只需几行:
use Whoops\Handler\PlainTextHandler; use Whoops\Run; $whoops = new Run(); $handler = new PlainTextHandler(); $handler->addTraceToOutput(true); $handler->addTraceFunctionArgsToOutput(3); $handler->setTraceFunctionArgsOutputLimit(1024); $whoops->pushHandler($handler); $whoops->register();
- 调用
addTraceToOutput(true)才显示调用栈,否则只报错消息 -
addTraceFunctionArgsToOutput(3)控制只显示最深 3 层的函数参数,防敏感数据泄露 - 若要写日志而非打印到屏幕,加
$handler->loggerOnly()并配setLogger() - 注意:它不替代
set_error_handler,而是接在set_exception_handler之后
致命错误(Fatal Error)怎么兜住
set_error_handler 和 set_exception_handler 都抓不到 Fatal error(比如调用不存在函数、内存耗尽)。唯一能捕获它的,是 register_shutdown_function + error_get_last()。
但要注意:shutdown function 是最后执行的,此时脚本已退出上下文,不能抛异常、不能 return,只能记录和 exit。
register_shutdown_function(function () {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
error_log("[FATAL] {$error['message']} in {$error['file']}:{$error['line']}");
fwrite(STDERR, "Fatal error: {$error['message']}\n");
exit(255);
}
});
- 必须检查
$error['type'],否则正常脚本结束也会触发 shutdown function - CLI 下写错误到
STDERR而不是echo,避免和 stdout 混淆 - exit 码建议用 255(POSIX 标准中表示异常终止),别用 0 或 1
- 这个机制无法恢复执行,只能保命式收尾——真正的健壮性得靠前期代码审查和类型约束
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











