PHP 8.0 的致命错误需通过 set_error_handler、set_exception_handler 和 register_shutdown_function 三者协同捕获:前者将传统错误转为 Error 异常,后者统一处理所有 Throwable,最后者兜底捕获 Parse/Compile 等早期致命错误。

PHP 8.0 的致命错误(如 Fatal error、Parse error、TypeError 等)默认无法被 try...catch 捕获,因为它们发生在脚本执行的更底层。但 PHP 8.0 提供了更可靠的机制来捕获并记录这些错误——核心是结合 set_error_handler、set_exception_handler 和 register_shutdown_function,并利用 error_get_last() 在脚本终止前做兜底处理。
启用所有错误报告并统一转为异常
在入口文件(如 index.php)开头启用严格错误报告,并将传统错误(E_ERROR、E_PARSE 等)转为 Error 异常,便于统一处理:
error_reporting(E_ALL);
ini_set('display_errors', '0'); // 生产环境务必关闭
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php/app-errors.log'); // 可选:PHP 自带日志路径
// 将错误转为 Error 异常(PHP 7+ 支持,8.0 更完善)
set_error_handler(function($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
return;
}
throw new Error($message, $severity);
});
用 set_exception_handler 捕获未捕获的异常和 Error
PHP 8.0 中 Error 类继承自 Throwable,因此 set_exception_handler 能同时捕获 Exception 和 Error(包括 FatalError 子类):
set_exception_handler(function(Throwable $e) {
$log = sprintf(
"[%s] %s: %s in %s:%d\nStack trace:\n%s\n",
date('Y-m-d H:i:s'),
get_class($e),
$e->getMessage(),
$e->getFile(),
$e->getLine(),
$e->getTraceAsString()
);
error_log($log, 3, '/var/log/php/app-fatal.log');
// 可选:返回友好的错误页或 JSON 响应
http_response_code(500);
echo "系统繁忙,请稍后再试。";
exit(1);
});
用 register_shutdown_function 做最后兜底(捕获 Parse Error 等)
某些解析期错误(如语法错误 Parse error、Compile error)在脚本加载阶段就终止,甚至绕过 set_error_handler 和 set_exception_handler。此时需用 register_shutdown_function 检查 error_get_last():
立即学习“PHP免费学习笔记(深入)”;
register_shutdown_function(function() {
if ($error = error_get_last()) {
// 仅处理致命类错误(不会被上面 handler 捕获的)
$fatalTypes = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR];
if (in_array($error['type'], $fatalTypes)) {
$log = sprintf(
"[%s] FATAL: %s in %s:%d\n",
date('Y-m-d H:i:s'),
$error['message'],
$error['file'],
$error['line']
);
error_log($log, 3, '/var/log/php/app-shutdown.log');
}
}
});
补充建议:日志格式与生产环境配置
确保日志可追溯、易排查:
- 使用结构化日志(如 JSON 格式),方便 ELK 或 Loki 收集;
- 避免在日志中记录敏感数据(如密码、token、用户身份证号);
- 确认 Web 服务器(Nginx/Apache)和 PHP-FPM 的错误日志级别一致,防止重复或遗漏;
- 对 CLI 脚本单独配置,因
register_shutdown_function行为在 CLI 和 Web 下略有差异; - 考虑用 Monolog 等成熟库替代原生
error_log,支持轮转、上下文、多通道等特性。



















