首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 異常處理最佳實踐:構建健壯的錯誤捕獲與日誌記錄機制

     編輯:PHP 相關知識

為什麼需要自定義異常處理?

PHP 預設的錯誤輸出會直接暴露文件路徑、代碼行號等敏感資訊,這在生產環境中構成安全風險。同時,預設機制缺乏靈活的日誌記錄、用戶友好提示與錯誤分級處理能力。通過 set_error_handler()、set_exception_handler() 與 register_shutdown_function() 三大核心函數,我們可以構建一套完整的異常處理體系。

核心架構設計

環境區分:開發與生產模式

透過常量 DEBUG 區分環境:

  • 開發模式(定義 DEBUG):啟用完整錯誤報告,直接顯示錯誤詳情,便於調試
  • 生產模式(未定義 DEBUG):關閉錯誤顯示,啟用自定義處理器,記錄日誌並返回友好提示
if (defined('DEBUG')) {
    error_reporting(E_ALL);
    ini_set("display_errors", 1);
}

致命錯誤捕獲:Shutdown Handler

PHP 的致命錯誤無法通過 set_error_handler 捕獲,需使用 register_shutdown_function 在腳本結束時檢查:

function shutdownHandler() {
    $lasterror = error_get_last();
    if ($lasterror) {
        // 記錄日誌
        $error = date("Y-m-d h:i:s") . '=>' . "[SHUTDOWN] lvl:" . $lasterror['type'] 
            . " | msg:" . $lasterror['message'] 
            . " | file:" . $lasterror['file'] 
            . " | ln:" . $lasterror['line'] . "\n";
        file_put_contents('./log/' . date("Ymd") . 'shutdownlog.txt', $error, FILE_APPEND);
        
        // 用戶友好提示
        ob_end_clean();
        die('對不起,系統出錯了!');
    }
}
register_shutdown_function('shutdownHandler');

標準錯誤轉異常:Error Handler

將所有 PHP 錯誤(除 Notice 與 Deprecated 外)轉為 ErrorException 統一處理:

function errorHandler($errno, $errstr = '', $errfile = '', $errline = 0) {
    $exception = new \ErrorException($errstr, 0, $errno, $errfile, $errline);
    $msg = date("Y-m-d h:i:s") . '=>' . 'Type:' . getErrTypeName($errno) . ' ' . getMsg($exception);
    file_put_contents('./log/' . date("Ymd") . 'error.txt', $msg, FILE_APPEND);
    
    // 忽略 Notice 與 Deprecated
    switch ($errno) {
        case E_NOTICE:
        case E_DEPRECATED:
            return;
    }
    throw $exception;
}
set_error_handler('errorHandler', E_ALL);

異常統一處理:Exception Handler

捕獲所有未被 try-catch 捕獲的異常,記錄完整堆疊資訊:

function exceptionHandler($ex) {
    $msg = date("Y-m-d h:i:s") . '=>' . getMsg($ex);
    file_put_contents('./log/' . date("Ymd") . 'exception.txt', $msg, FILE_APPEND);
}
set_exception_handler('exceptionHandler');

輔助函數:錯誤類型名稱與訊息提取

function getErrTypeName($errno) {
    switch ($errno) {
        case E_NOTICE: return 'E_NOTICE';
        case E_DEPRECATED: return 'E_DEPRECATED';
        default: return $errno;
    }
}

function getMsg($exception) {
    // 獲取最原始的異常(處理 Previous 鏈)
    while ($exception->getPrevious()) {
        $exception = $exception->getPrevious();
    }
    $msg = ' Message: ' . $exception->getMessage();
    $msg .= ' File: ' . $exception->getFile() . ':' . $exception->getLine() . "\n";
    return $msg;
}

日誌結構建議

程式碼按日期自動分割日誌文件:

  • shutdownlog.txt - 致命錯誤日誌
  • error.txt - 標準錯誤日誌
  • exception.txt - 異常日誌

建議在生產環境配置 logrotate 定期清理舊日誌,避免磁碟佔用過大。

部署注意事項

  1. 日誌目錄權限:確保 ./log/ 目錄可寫入
  2. 錯誤頁面美化:將 die() 替換為載入專用錯誤模板頁面
  3. 監控告警:配合 ELK、Promtail 等工具採集日誌,設置關鍵錯誤告警
  4. 敏感資訊過濾:生產環境日誌中避免記錄用戶密碼、Token 等敏感字段

適用版本:PHP 5.3+
核心函數:set_error_handler、set_exception_handler、register_shutdown_function、error_get_last

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved