set_error_handler仅能捕获E_WARNING、E_NOTICE等非致命错误,无法捕获语法错误、E_ERROR等致命错误;需用register_shutdown_function辅助检测,并注意避免处理器自身出错导致递归。

PHP 的 set_error_handler 可以捕获运行时的非致命错误(如 E_WARNING、E_NOTICE、E_USER_ERROR 等),但**不能捕获语法错误、致命错误(E_ERROR)、解析错误或 PHP 启动阶段的错误**。它主要用于自定义错误提示、记录日志或做兜底处理,而不是“修复”错误。
基本用法:定义并注册错误处理器
你需要提供一个回调函数,它会在触发可捕获错误时被自动调用。该函数必须接收至少两个参数:$errno(错误级别)和 $errstr(错误信息):
- 函数签名示例:
function($errno, $errstr, $errfile, $errline) - 前两个参数是必需的;后两个(文件名、行号)是可选的,但强烈建议加上以便定位问题
- 函数返回
true表示你已处理该错误,PHP 将不再执行默认错误报告;返回false或不返回,则交由系统默认处理(如显示错误或写入日志)
常见错误级别说明与过滤
不是所有错误都适合统一捕获。建议在处理器中先判断错误类型,避免干扰调试或掩盖严重问题:
-
E_WARNING、E_NOTICE、E_USER_WARNING、E_USER_NOTICE:常用于捕获并记录 -
E_USER_ERROR、E_USER_WARNING、E_USER_NOTICE:由trigger_error()主动抛出,适合统一拦截 -
E_ERROR、E_PARSE、E_CORE_ERROR等:无法被set_error_handler捕获,需靠register_shutdown_function+error_get_last()辅助检测 - 建议开头加判断:
if (!(error_reporting() & $errno)) { return false; },确保只处理当前错误报告级别允许的错误
实际使用示例(带日志与抑制输出)
下面是一个轻量实用的错误处理器,将警告/通知类错误写入日志,并阻止页面直接显示:
立即学习“PHP免费学习笔记(深入)”;
function myErrorHandler($errno, $errstr, $errfile, $errline) {
// 忽略未启用的错误级别
if (!(error_reporting() & $errno)) {
return false;
}
// 分类处理
$level = [
E_WARNING => 'WARNING',
E_NOTICE => 'NOTICE',
E_USER_WARNING => 'USER_WARNING',
E_USER_NOTICE => 'USER_NOTICE',
][$errno] ?? 'UNKNOWN';
$message = "[$level] $errstr in $errfile on line $errline";
error_log($message, 3, '/tmp/php_errors.log'); // 写入日志
// 可选:开发环境显示,生产环境静默
if (defined('DEBUG') && DEBUG) {
echo "<div style='color:red;font-size:12px;'>$message</div>";
}
return true; // 已处理,不走默认流程
}
// 注册处理器
set_error_handler('myErrorHandler');
// 测试
echo $undefined_var; // 触发 NOTICE
trigger_error('这是个用户警告', E_USER_WARNING); // 触发 USER_WARNING
注意事项与常见陷阱
使用时容易忽略的关键点:
- 处理器本身若出错(比如访问了不存在的全局变量),会导致无限递归或脚本崩溃,建议在处理器内尽量避免复杂逻辑和外部依赖
- 不能捕获
require/include导致的致命错误(如文件不存在引发的E_COMPILE_ERROR),这类要用set_exception_handler配合异常包装或提前检查文件存在性 - 如果启用了
display_errors=On,即使你返回true,某些错误仍可能被显示——需配合ini_set('display_errors', 'Off')使用 - 多个
set_error_handler调用会覆盖前一个,如需链式处理,可用set_error_handler返回旧处理器,再手动调用它



















