這篇文章主要介紹了一個顯示效果非常不錯的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; }