這篇文章主要介紹了一個顯示效果非常不錯的PHP錯誤、異常處理類,代碼思路清晰,功能強大,需要的朋友可以參考下
一、效果圖:

二、實現代碼
代碼如下:<?php
// 自定義異常函數
set_exception_handler('handle_exception');
// 自定義錯誤函數
set_error_handler('handle_error');
/**
* 異常處理
*
* @param mixed $exception 異常對象
* @author blog.snsgou.com
*/
function handle_exception($exception) {
Error::exceptionError($exception);
}
/**
* 錯誤處理
*
* @param string $errNo 錯誤代碼
* @param string $errStr 錯誤信息
* @param string $errFile 出錯文件
* @param string $errLine 出錯行
* @author blog.snsgou.com
*/
function handle_error($errNo, $errStr, $errFile, $errLine) {
if ($errNo) {
Error::systemError($errStr, false, true, false);
}
}
/**
* 系統錯誤處理
*
* @author blog.snsgou.com
*/
class Error {
public static function systemError($message, $show = true, $save = true, $halt = true) {
list($showTrace, $logTrace) = self::debugBacktrace();
if ($save) {
$messageSave = '<b>' . $message . '</b><br /><b>PHP:</b>' . $logTrace;
self::writeErrorLog($messageSave);
}
if ($show) {
self::showError('system', "<li>$message</li>", $showTrace, 0);
}
if ($halt) {
exit();
} else {
return $message;
}
}
/**
* 代碼執行過程回溯信息
*
* @static
* @access public
*/
public static function debugBacktrace() {
$skipFunc[] = 'Error->debugBacktrace';
$show = $log = '';
$debugBacktrace = debug_backtrace();
ksort($debugBacktrace);
foreach ($debugBacktrace as $k => $error) {
if (!isset($error['file'])) {
// 利用反射API來獲取方法/函數所在的文件和行數
try {
if (isset($error['class'])) {
$reflection = new ReflectionMethod($error['class'], $error['function']);
} else {
$reflection = new ReflectionFunction($error['function']);
}
$error['file'] = $reflection->getFileName();
$error['line'] = $reflection->getStartLine();
} catch (Exception $e) {
continue;
}
}
$file = str_replace(SITE_PATH, '', $error['file']);
$func = isset($error['class']) ? $error['class'] : '';
$func .= isset($error['type']) ? $error['type'] : '';
$func .= isset($error['function']) ? $error['function'] : '';
if (in_array($func, $skipFunc)) {
break;
}
$error['line'] = sprintf('%04d', $error['line']);
$show .= '<li>[Line: ' . $error['line'] . ']' . $file . '(' . $func . ')</li>';
$log .= !empty($log) ? ' -> ' : '';
$log .= $file . ':' . $error['line'];
}
return array($show, $log);
}
/**
* 異常處理
*
* @static
* @access public
* @param mixed $exception
*/
public static function exceptionError($exception) {
if ($exception instanceof DbException) {
$type = 'db';
} else {
$type = 'system';
}
if ($type == 'db') {
$errorMsg = '(' . $exception->getCode() . ') ';
$errorMsg .= self::sqlClear($exception->getMessage(), $exception->getDbConfig());
if ($exception->getSql()) {
$errorMsg .= '<div class="sql">';
$errorMsg .= self::sqlClear($exception->getSql(), $exception->getDbConfig());
$errorMsg .= '</div>';
}
} else {
$errorMsg = $exception->getMessage();
}
$trace = $exception->getTrace();
krsort($trace);
$trace[] = array('file' => $exception->getFile(), 'line' => $exception->getLine(), 'function' => 'break');
$phpMsg = array();
foreach ($trace as $error) {
if (!empty($error['function'])) {
$fun = '';
if (!empty($error['class'])) {
$fun .= $error['class'] . $error['type'];
}
$fun .= $error['function'] . '(';
if (!empty($error['args'])) {
$mark = '';
foreach ($error['args'] as $arg) {
$fun .= $mark;
if (is_array($arg)) {
$fun .= 'Array';
} elseif (is_bool($arg)) {
$fun .= $arg ? 'true' : 'false';
} elseif (is_int($arg)) {
$fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? $arg : '%d';
} elseif (is_float($arg)) {
$fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? $arg : '%f';
} else {
$fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? ''' . htmlspecialchars(substr(self::clear($arg), 0, 10)) . (strlen($arg) > 10 ? ' ...' : '') . ''' : '%s';
}
$mark = ', ';
}
}
$fun .= ')';
$error['function'] = $fun;
}
if (!isset($error['line'])) {
continue;
}
$phpMsg[] = array('file' => str_replace(array(SITE_PATH, ''), array('', '/'), $error['file']), 'line' => $error['line'], 'function' => $error['function']);
}
self::showError($type, $errorMsg, $phpMsg);
exit();
}
/**
* 記錄錯誤日志
*
* @static
* @access public
* @param string $message
*/
public static function writeErrorLog($message) {
return false; // 暫時不寫入
$message = self::clear($message);
$time = time();
$file = LOG_PATH . '/' . date('Y.m.d') . '_errorlog.php';
$hash = md5($message);
$userId = 0;
$ip = get_client_ip();
$user = '<b>User:</b> userId=' . intval($userId) . '; IP=' . $ip . '; RIP:' . $_SERVER['REMOTE_ADDR'];
$uri = 'Request: ' . htmlspecialchars(self::clear($_SERVER['REQUEST_URI']));
$message = "<?php exit;?>t{$time}t$messaget$hasht$user $urin";
// 判斷該$message是否在時間間隔$maxtime內已記錄過,有,則不用再記錄了
if (is_file($file)) {
$fp = @fopen($file, 'rb');
$lastlen = 50000; // 讀取最後的 $lastlen 長度字節內容
$maxtime = 60 * 10; // 時間間隔:10分鐘
$offset = filesize($file) - $lastlen;
if ($offset > 0) {
fseek($fp, $offset);
}
if ($data = fread($fp, $lastlen)) {
$array = explode("n", $data);
if (is_array($array))
foreach ($array as $key => $val) {
$row = explode("t", $val);
if ($row[0] != '<?php exit;?>') {
continue;
}