set_error_handler() 是PHP内置的错误处理函数,用于设置用户自定义的错误处理函数。通过这个函数,开发者可以定义自己的错误处理逻辑,替代PHP的默认错误处理机制,从而实现更灵活的错误处理、日志记录和调试。
register_shutdown_function()配合error_get_last()。
mixed set_error_handler(callable $error_handler[, int $error_types = E_ALL | E_STRICT])
函数返回之前定义的错误处理程序,或者在出错时返回null。
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| $error_handler | callable | 必填 |
自定义的错误处理函数。可以是一个函数名、类方法数组或匿名函数。这个函数需要接受5个参数: 1. $errno - 错误级别 2. $errstr - 错误信息 3. $errfile - 发生错误的文件名 4. $errline - 发生错误的行号 5. $errcontext - 错误发生时活动符号表的数组(PHP 7.2.0+已弃用) |
| $error_types | int | E_ALL | E_STRICT | 指定哪些错误类型应该被这个错误处理器处理。可以是错误级别常量的位掩码组合。如果没有设置,默认处理所有错误类型。 |
mixed - 返回之前定义的错误处理程序,或者在出错时返回null。
可能的返回值:
演示如何使用set_error_handler()设置基本的自定义错误处理器:
<?php
// 自定义错误处理函数
function customErrorHandler($errno, $errstr, $errfile, $errline) {
echo "<div style='background:#f8d7da; padding:10px; margin:5px; border:1px solid #f5c6cb;'>";
echo "<strong>自定义错误处理器捕获到错误:</strong><br>";
echo "错误级别: " . $errno . "<br>";
echo "错误信息: " . htmlspecialchars($errstr) . "<br>";
echo "错误文件: " . $errfile . "<br>";
echo "错误行号: " . $errline;
echo "</div>";
// 返回true表示错误已处理,阻止PHP执行默认错误处理器
return true;
}
// 设置自定义错误处理器
$previousHandler = set_error_handler("customErrorHandler");
echo "<h4>测试错误处理:</h4>";
// 触发不同类型的错误
echo $undefinedVariable; // 注意:使用未定义的变量(E_NOTICE)
$result = 10 / 0; // 警告:除以零(E_WARNING)
// 恢复之前的错误处理器
restore_error_handler();
echo "<div class='alert alert-info'>";
echo "已恢复之前的错误处理器";
echo "</div>";
演示如何使用匿名函数作为错误处理器:
<?php
// 使用匿名函数作为错误处理器
$errorHandler = function($errno, $errstr, $errfile, $errline) {
$errorTypes = [
1 => 'E_ERROR',
2 => 'E_WARNING',
8 => 'E_NOTICE',
256 => 'E_USER_ERROR',
512 => 'E_USER_WARNING',
1024 => 'E_USER_NOTICE',
4096 => 'E_RECOVERABLE_ERROR',
8192 => 'E_DEPRECATED',
16384 => 'E_USER_DEPRECATED',
];
$errorName = isset($errorTypes[$errno]) ? $errorTypes[$errno] : "未知错误($errno)";
$log = sprintf(
"[%s] [%s] %s in %s on line %d\n",
date('Y-m-d H:i:s'),
$errorName,
$errstr,
$errfile,
$errline
);
// 记录到日志文件
file_put_contents('error.log', $log, FILE_APPEND);
// 如果是开发环境,也显示错误
if (getenv('APP_ENV') === 'development') {
echo "<div style='background:#fff3cd; padding:10px; margin:5px; border:1px solid #ffeaa7;'>";
echo "<strong>错误:</strong> " . htmlspecialchars($errstr) . "<br>";
echo "<strong>位置:</strong> " . $errfile . " 第 " . $errline . " 行";
echo "</div>";
}
return true; // 阻止PHP默认错误处理器
};
// 设置错误处理器
set_error_handler($errorHandler);
echo "<h4>测试匿名函数错误处理器:</h4>";
// 触发错误
strpos(); // 警告:缺少参数
// 查看错误日志
if (file_exists('error.log')) {
echo "<div class='alert alert-success'>";
echo "错误已记录到日志文件";
echo "</div>";
}
演示如何在类中使用set_error_handler():
<?php
// 错误处理类
class ErrorHandler {
private $logFile = 'app_errors.log';
public function __construct($logFile = null) {
if ($logFile) {
$this->logFile = $logFile;
}
// 设置错误处理器
set_error_handler([$this, 'handleError']);
}
public function handleError($errno, $errstr, $errfile, $errline) {
// 构建错误信息
$errorInfo = [
'timestamp' => date('Y-m-d H:i:s'),
'errno' => $errno,
'errstr' => $errstr,
'errfile' => $errfile,
'errline' => $errline,
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
'uri' => $_SERVER['REQUEST_URI'] ?? 'unknown',
];
// 记录到日志
$this->logError($errorInfo);
// 根据错误级别处理
switch ($errno) {
case E_USER_ERROR:
case E_RECOVERABLE_ERROR:
$this->handleFatalError($errorInfo);
break;
case E_USER_WARNING:
case E_WARNING:
$this->handleWarning($errorInfo);
break;
case E_USER_NOTICE:
case E_NOTICE:
case E_DEPRECATED:
case E_USER_DEPRECATED:
$this->handleNotice($errorInfo);
break;
default:
$this->handleUnknownError($errorInfo);
}
return true; // 阻止PHP默认处理器
}
private function logError($errorInfo) {
$logEntry = sprintf(
"[%s] [Level:%d] %s in %s:%d (IP:%s, URI:%s)\n",
$errorInfo['timestamp'],
$errorInfo['errno'],
$errorInfo['errstr'],
$errorInfo['errfile'],
$errorInfo['errline'],
$errorInfo['ip'],
$errorInfo['uri']
);
file_put_contents($this->logFile, $logEntry, FILE_APPEND);
}
private function handleFatalError($errorInfo) {
// 发送邮件通知等
error_log("严重错误: " . $errorInfo['errstr']);
// 显示用户友好的错误页面
if (php_sapi_name() !== 'cli') {
echo "<div style='text-align:center; padding:50px;'>";
echo "<h1 style='color:#dc3545;'>系统错误</h1>";
echo "<p>抱歉,系统发生了内部错误。我们的技术团队已收到通知。</p>";
echo "</div>";
}
}
private function handleWarning($errorInfo) {
// 开发环境显示警告
if (getenv('APP_ENV') === 'development') {
echo "<div style='background:#fff3cd; padding:10px; margin:5px; border:1px solid #ffeaa7;'>";
echo "<strong>警告:</strong> " . htmlspecialchars($errorInfo['errstr']);
echo "</div>";
}
}
private function handleNotice($errorInfo) {
// 开发环境显示通知
if (getenv('APP_ENV') === 'development') {
echo "<div style='background:#e7f3ff; padding:10px; margin:5px; border:1px solid #b3d7ff;'>";
echo "<strong>注意:</strong> " . htmlspecialchars($errorInfo['errstr']);
echo "</div>";
}
}
private function handleUnknownError($errorInfo) {
// 处理未知错误类型
error_log("未知错误: " . $errorInfo['errstr']);
}
public function __destruct() {
// 恢复错误处理器
restore_error_handler();
}
}
// 使用示例
echo "<h4>使用ErrorHandler类:</h4>";
// 设置环境变量
putenv('APP_ENV=development');
$handler = new ErrorHandler();
// 触发不同类型的错误
trigger_error("用户自定义错误", E_USER_ERROR);
trigger_error("用户自定义警告", E_USER_WARNING);
trigger_error("用户自定义通知", E_USER_NOTICE);
echo "<div class='alert alert-info'>";
echo "查看 app_errors.log 文件获取详细错误日志";
echo "</div>";
演示如何使用$error_types参数过滤错误级别:
<?php
// 只处理错误和警告的处理器
function errorAndWarningHandler($errno, $errstr, $errfile, $errline) {
echo "<div style='background:#f8d7da; padding:10px; margin:5px; border:1px solid #f5c6cb;'>";
echo "<strong>错误/警告处理器:</strong> " . htmlspecialchars($errstr);
echo "</div>";
return true;
}
// 只处理通知的处理器
function noticeHandler($errno, $errstr, $errfile, $errline) {
echo "<div style='background:#e7f3ff; padding:10px; margin:5px; border:1px solid #b3d7ff;'>";
echo "<strong>通知处理器:</strong> " . htmlspecialchars($errstr);
echo "</div>";
return true;
}
// 只处理用户错误的处理器
function userErrorHandler($errno, $errstr, $errfile, $errline) {
echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
echo "<strong>用户错误处理器:</strong> " . htmlspecialchars($errstr);
echo "</div>";
return true;
}
echo "<h4>测试错误级别过滤:</h4>";
// 1. 只处理错误和警告
set_error_handler("errorAndWarningHandler", E_ERROR | E_WARNING | E_USER_ERROR | E_USER_WARNING);
echo "<p>1. 当前处理器: 只处理错误和警告</p>";
trigger_error("用户警告测试", E_USER_WARNING); // 会被处理
trigger_error("用户通知测试", E_USER_NOTICE); // 不会被处理(PHP默认处理器处理)
// 2. 只处理通知
set_error_handler("noticeHandler", E_NOTICE | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED);
echo "<p>2. 当前处理器: 只处理通知</p>";
trigger_error("用户通知测试2", E_USER_NOTICE); // 会被处理
trigger_error("用户警告测试2", E_USER_WARNING); // 不会被处理
// 3. 恢复默认处理器
restore_error_handler();
echo "<p>3. 当前处理器: PHP默认处理器</p>";
trigger_error("用户错误测试", E_USER_ERROR); // PHP默认处理器处理
// 4. 复杂的错误级别组合
echo "<h4>复杂的错误级别组合:</h4>";
// 处理除弃用警告外的所有错误
set_error_handler("errorAndWarningHandler", E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
// 或者:处理所有错误,但排除通知
set_error_handler("errorAndWarningHandler", E_ALL & ~E_NOTICE & ~E_USER_NOTICE);
echo "<div class='alert alert-info'>";
echo "可以使用位运算符组合错误级别:";
echo "<ul>";
echo "<li>E_ALL | E_STRICT - 包含所有错误</li>";
echo "<li>E_ALL & ~E_DEPRECATED - 排除弃用警告</li>";
echo "<li>E_ERROR | E_WARNING | E_PARSE - 只处理错误、警告和解析错误</li>";
echo "</ul>";
echo "</div>";
创建一个完整的错误处理系统,包括错误处理、异常处理和致命错误处理:
<?php
/**
* 完整的错误处理系统
*/
class AppErrorHandler {
private static $instance = null;
private $logFile = 'logs/app.log';
private $errorLogFile = 'logs/errors.log';
private $environment = 'production';
private function __construct() {
$this->environment = getenv('APP_ENV') ?: 'production';
// 确保日志目录存在
$this->ensureLogDirectory();
// 设置错误处理器
$this->setupErrorHandling();
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
private function ensureLogDirectory() {
$logDir = dirname($this->logFile);
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
}
private function setupErrorHandling() {
// 设置错误报告级别
if ($this->environment === 'development') {
error_reporting(E_ALL);
ini_set('display_errors', 0); // 我们自定义显示
} else {
error_reporting(E_ERROR | E_WARNING | E_PARSE);
ini_set('display_errors', 0);
}
// 设置自定义错误处理器
set_error_handler([$this, 'handleError']);
// 设置自定义异常处理器
set_exception_handler([$this, 'handleException']);
// 设置关闭函数处理致命错误
register_shutdown_function([$this, 'handleShutdown']);
}
public function handleError($errno, $errstr, $errfile, $errline) {
$error = [
'type' => 'ERROR',
'level' => $this->getErrorLevelName($errno),
'message' => $errstr,
'file' => $errfile,
'line' => $errline,
'timestamp' => date('Y-m-d H:i:s'),
'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5),
];
// 记录错误
$this->logError($error);
// 处理错误
$this->processError($error);
// 如果是致命错误,不要返回true(让PHP处理)
if (in_array($errno, [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
return false;
}
return true; // 阻止PHP默认处理器
}
public function handleException($exception) {
$error = [
'type' => 'EXCEPTION',
'level' => 'EXCEPTION',
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'timestamp' => date('Y-m-d H:i:s'),
'backtrace' => $exception->getTrace(),
];
// 记录异常
$this->logError($error);
// 处理异常
$this->processError($error, $exception);
// 如果是控制台模式,输出错误
if (php_sapi_name() === 'cli') {
fwrite(STDERR, "未捕获异常: " . $exception->getMessage() . "\n");
}
}
public function handleShutdown() {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
$fatalError = [
'type' => 'FATAL',
'level' => 'FATAL',
'message' => $error['message'],
'file' => $error['file'],
'line' => $error['line'],
'timestamp' => date('Y-m-d H:i:s'),
];
// 记录致命错误
$this->logError($fatalError);
// 处理致命错误
$this->processFatalError($fatalError);
}
}
private function getErrorLevelName($errno) {
$levels = [
1 => 'E_ERROR',
2 => 'E_WARNING',
4 => 'E_PARSE',
8 => 'E_NOTICE',
16 => 'E_CORE_ERROR',
32 => 'E_CORE_WARNING',
64 => 'E_COMPILE_ERROR',
128 => 'E_COMPILE_WARNING',
256 => 'E_USER_ERROR',
512 => 'E_USER_WARNING',
1024 => 'E_USER_NOTICE',
2048 => 'E_STRICT',
4096 => 'E_RECOVERABLE_ERROR',
8192 => 'E_DEPRECATED',
16384 => 'E_USER_DEPRECATED',
];
return isset($levels[$errno]) ? $levels[$errno] : "UNKNOWN($errno)";
}
private function logError($error) {
$logEntry = sprintf(
"[%s] [%s] [%s] %s in %s on line %d\n",
$error['timestamp'],
$error['type'],
$error['level'],
$error['message'],
$error['file'],
$error['line']
);
// 记录到错误日志
file_put_contents($this->errorLogFile, $logEntry, FILE_APPEND);
// 记录到应用日志
if ($this->environment === 'development') {
$fullLog = $logEntry;
if (isset($error['backtrace'])) {
$fullLog .= "Backtrace:\n";
foreach ($error['backtrace'] as $i => $trace) {
$fullLog .= sprintf("#%d %s:%d\n", $i,
$trace['file'] ?? 'unknown',
$trace['line'] ?? 0
);
}
}
file_put_contents($this->logFile, $fullLog, FILE_APPEND);
}
}
private function processError($error, $exception = null) {
// 根据环境处理错误
if ($this->environment === 'development') {
$this->displayDebugError($error, $exception);
} else {
$this->displayUserFriendlyError($error);
}
// 发送通知(邮件、Slack等)
if (in_array($error['level'], ['E_ERROR', 'E_USER_ERROR', 'EXCEPTION', 'FATAL'])) {
$this->sendErrorNotification($error);
}
}
private function processFatalError($error) {
if (php_sapi_name() !== 'cli' && $this->environment === 'production') {
// 显示用户友好的错误页面
$this->displayFatalErrorPage();
}
}
private function displayDebugError($error, $exception = null) {
if (php_sapi_name() !== 'cli') {
echo "<div style='background:#f8f9fa; padding:15px; margin:10px; border:1px solid #ddd; font-family:monospace;'>";
echo "<h3 style='color:#dc3545; margin-top:0;'>错误详情</h3>";
echo "<table style='width:100%; border-collapse:collapse;'>";
echo "<tr><td style='width:100px; padding:5px; font-weight:bold;'>类型:</td><td style='padding:5px;'>" . $error['type'] . "</td></tr>";
echo "<tr><td style='padding:5px; font-weight:bold;'>级别:</td><td style='padding:5px;'>" . $error['level'] . "</td></tr>";
echo "<tr><td style='padding:5px; font-weight:bold;'>消息:</td><td style='padding:5px;'>" . htmlspecialchars($error['message']) . "</td></tr>";
echo "<tr><td style='padding:5px; font-weight:bold;'>文件:</td><td style='padding:5px;'>" . $error['file'] . "</td></tr>";
echo "<tr><td style='padding:5px; font-weight:bold;'>行号:</td><td style='padding:5px;'>" . $error['line'] . "</td></tr>";
echo "<tr><td style='padding:5px; font-weight:bold;'>时间:</td><td style='padding:5px;'>" . $error['timestamp'] . "</td></tr>";
echo "</table>";
if ($exception instanceof Exception) {
echo "<h4>异常堆栈:</h4>";
echo "<pre style='background:#e9ecef; padding:10px; border:1px solid #ddd; overflow:auto;'>";
echo htmlspecialchars($exception->getTraceAsString());
echo "</pre>";
}
if (isset($error['backtrace'])) {
echo "<h4>调用堆栈:</h4>";
echo "<pre style='background:#e9ecef; padding:10px; border:1px solid #ddd; overflow:auto;'>";
foreach ($error['backtrace'] as $i => $trace) {
echo "#" . $i . " ";
if (isset($trace['file'])) {
echo $trace['file'] . "(" . ($trace['line'] ?? 0) . "): ";
}
if (isset($trace['class'])) {
echo $trace['class'] . $trace['type'];
}
if (isset($trace['function'])) {
echo $trace['function'] . "()";
}
echo "\n";
}
echo "</pre>";
}
echo "</div>";
}
}
private function displayUserFriendlyError($error) {
if (php_sapi_name() !== 'cli') {
// 显示用户友好的错误信息
if (in_array($error['level'], ['E_ERROR', 'E_USER_ERROR', 'EXCEPTION', 'FATAL'])) {
echo "<div style='text-align:center; padding:50px;'>";
echo "<h1 style='color:#dc3545;'>系统错误</h1>";
echo "<p>抱歉,系统发生了内部错误。我们的技术团队已收到通知。</p>";
echo "<p><a href='/'>返回首页</a></p>";
echo "</div>";
}
}
}
private function displayFatalErrorPage() {
echo "<!DOCTYPE html>";
echo "<html><head><title>系统错误</title><style>";
echo "body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }";
echo "h1 { color: #dc3545; }";
echo "</style></head><body>";
echo "<h1>系统错误</h1>";
echo "<p>抱歉,系统发生了严重的内部错误。</p>";
echo "<p>我们的技术团队已收到通知,正在处理此问题。</p>";
echo "</body></html>";
}
private function sendErrorNotification($error) {
// 这里可以发送邮件、Slack通知等
// 示例:发送到错误监控服务
$notification = sprintf(
"[%s] 严重错误: %s in %s:%d",
$error['timestamp'],
$error['message'],
$error['file'],
$error['line']
);
error_log($notification);
}
}
// 使用示例
echo "<h4>使用完整的错误处理系统:</h4>";
// 设置环境
putenv('APP_ENV=development');
// 初始化错误处理系统
AppErrorHandler::getInstance();
// 测试不同类型的错误
echo "<h5>1. 测试用户错误:</h5>";
trigger_error("这是一个用户自定义错误", E_USER_ERROR);
echo "<h5>2. 测试警告:</h5>";
trigger_error("这是一个用户自定义警告", E_USER_WARNING);
echo "<h5>3. 测试异常:</h5>";
try {
throw new Exception("这是一个未捕获的异常");
} catch (Exception $e) {
// 这里不会捕获,因为会被异常处理器处理
}
echo "<div class='alert alert-success'>";
echo "查看 logs/ 目录下的日志文件获取详细错误信息";
echo "</div>";
演示在实际应用场景中如何使用错误处理器:
<?php
// 数据库操作类
class Database {
private $connection;
private static $errorHandlerSet = false;
public function __construct($host, $username, $password, $database) {
// 设置数据库错误处理器
if (!self::$errorHandlerSet) {
$this->setDatabaseErrorHandler();
self::$errorHandlerSet = true;
}
// 连接数据库
$this->connection = mysqli_connect($host, $username, $password, $database);
if (!$this->connection) {
throw new Exception("数据库连接失败: " . mysqli_connect_error());
}
}
private function setDatabaseErrorHandler() {
set_error_handler(function($errno, $errstr, $errfile, $errline) {
// 只处理数据库相关的错误
if (strpos($errstr, 'mysqli') !== false ||
strpos($errstr, 'mysql') !== false) {
// 记录数据库错误
$log = sprintf(
"[%s] 数据库错误: %s in %s:%d\n",
date('Y-m-d H:i:s'),
$errstr,
$errfile,
$errline
);
file_put_contents('database_errors.log', $log, FILE_APPEND);
// 抛出异常,让上层代码处理
throw new Exception("数据库操作失败: " . $errstr);
}
// 非数据库错误传递给下一个处理器
return false;
}, E_WARNING | E_NOTICE);
}
public function query($sql) {
$result = mysqli_query($this->connection, $sql);
if (!$result) {
throw new Exception("查询失败: " . mysqli_error($this->connection));
}
return $result;
}
public function __destruct() {
if ($this->connection) {
mysqli_close($this->connection);
}
// 恢复错误处理器
if (self::$errorHandlerSet) {
restore_error_handler();
self::$errorHandlerSet = false;
}
}
}
// API响应类
class ApiResponse {
public static function error($message, $code = 500, $data = []) {
$response = [
'success' => false,
'error' => [
'code' => $code,
'message' => $message,
'timestamp' => date('c'),
],
'data' => $data,
];
header('Content-Type: application/json');
http_response_code($code);
echo json_encode($response, JSON_PRETTY_PRINT);
exit;
}
}
// API错误处理器
class ApiErrorHandler {
public static function register() {
set_error_handler([self::class, 'handleError']);
set_exception_handler([self::class, 'handleException']);
}
public static function handleError($errno, $errstr, $errfile, $errline) {
// 记录错误
error_log("API错误: " . $errstr);
// 返回JSON错误响应
ApiResponse::error("服务器内部错误", 500, [
'error_type' => 'PHP_ERROR',
'error_message' => $errstr,
]);
return true;
}
public static function handleException($exception) {
// 记录异常
error_log("API异常: " . $exception->getMessage());
// 返回JSON错误响应
ApiResponse::error("服务器内部错误", 500, [
'error_type' => 'EXCEPTION',
'error_message' => $exception->getMessage(),
]);
}
}
// 使用示例
echo "<h4>场景1:数据库错误处理</h4>";
try {
// 模拟数据库连接
$db = new Database('localhost', 'wrong_user', 'wrong_pass', 'nonexistent_db');
} catch (Exception $e) {
echo "<div class='alert alert-danger'>";
echo "数据库错误: " . $e->getMessage();
echo "</div>";
}
echo "<h4>场景2:API错误处理</h4>";
// 注册API错误处理器
ApiErrorHandler::register();
// 模拟API错误
if (isset($_GET['test_error'])) {
// 这个错误会被ApiErrorHandler处理
trigger_error("测试API错误处理");
}
echo "<div class='alert alert-info'>";
echo "API错误处理器已注册,错误将返回JSON格式的响应";
echo "</div>";
记录错误到自定义格式的日志文件或数据库中,便于后续分析和监控。
显示用户友好的错误页面,而不是PHP的默认错误信息,提升用户体验。
当发生严重错误时,自动发送邮件、短信或Slack通知给开发团队。
set_error_handler()不能处理致命错误(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_COMPILE_WARNING)。需要使用register_shutdown_function()配合error_get_last()来处理。@错误抑制操作符时,错误会被抑制,不会传递给自定义错误处理器。true表示错误已被处理,PHP不会执行默认的错误处理器。返回false会继续传递给下一个错误处理器。set_error_handler()会创建错误处理器栈,可以使用restore_error_handler()恢复上一个处理器。$errcontext在PHP 7.2.0中已弃用,不推荐使用。set_exception_handler())应该协同工作,提供完整的错误处理解决方案。根据不同的环境(开发、测试、生产)使用不同的错误处理策略:
function setupErrorHandling() {
$env = getenv('APP_ENV');
if ($env === 'development') {
// 开发环境:显示详细错误
error_reporting(E_ALL);
set_error_handler('devErrorHandler');
} else {
// 生产环境:记录日志但不显示
error_reporting(E_ERROR | E_WARNING);
set_error_handler('prodErrorHandler');
}
}
记录结构化的错误信息,便于日志分析:
function logError($errno, $errstr, $errfile, $errline) {
$log = json_encode([
'timestamp' => date('c'),
'level' => $errno,
'message' => $errstr,
'file' => $errfile,
'line' => $errline,
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5)
], JSON_PRETTY_PRINT);
file_put_contents('error.log', $log . "\n", FILE_APPEND);
}
创建统一的错误处理入口,管理所有错误处理逻辑:
class ErrorManager {
public static function init() {
set_error_handler([self::class, 'handleError']);
set_exception_handler([self::class, 'handleException']);
register_shutdown_function([self::class, 'handleShutdown']);
}
public static function handleError($errno, $errstr, $errfile, $errline) {
// 统一错误处理逻辑
}
}
编写测试来验证错误处理器的行为:
function testErrorHandler() {
set_error_handler('testHandler');
// 触发不同类型的错误
trigger_error('Test error', E_USER_ERROR);
trigger_error('Test warning', E_USER_WARNING);
// 验证错误被正确处理
assert(file_exists('test.log'));
restore_error_handler();
}