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

PHP 錯誤處理與異常處理完整筆記(從 die() 到 try-catch)

     編輯:PHP 相關知識

妥善的錯誤與異常處理能提升使用者體驗、加速除錯、降低安全風險並增強系統健壯性。本文系統梳理 PHP 的錯誤處理機制、自定義錯誤處理器、錯誤日誌記錄與異常處理最佳實踐。

一、為什麼需要錯誤處理?

  • 對使用者友善:避免白屏或暴露堆疊追蹤。
  • 便於除錯:集中記錄、分級告警。
  • 安全性:不洩露路徑、資料庫結構等敏感資訊。
  • 健壯性:優雅降級、資源釋放、事務回滾。

二、錯誤處理層級對照表

值常數說明備註
1E_ERROR致命執行錯誤,腳本終止不可被自定義處理器捕獲
2E_WARNING執行警告,腳本繼續
4E_PARSE編譯期語法解析錯誤
8E_NOTICE執行期通知(如未定義變數)
16E_CORE_ERRORPHP 啟動致命錯誤PHP 4+
32E_CORE_WARNINGPHP 啟動警告PHP 4+
64E_COMPILE_ERROR編譯致命錯誤PHP 4+
128E_COMPILE_WARNING編譯警告PHP 4+
256E_USER_ERROR用戶觸發致命錯誤PHP 4+,trigger_error()
512E_USER_WARNING用戶觸發警告PHP 4+
1024E_USER_NOTICE用戶觸發通知PHP 4+
2048E_STRICT程式碼改進建議PHP 5+
4096E_RECOVERABLE_ERROR可捕獲的致命錯誤PHP 5.2+,可被自定義處理器捕獲
8192E_DEPRECATED棄用警告PHP 5.3+
16384E_USER_DEPRECATED用戶觸發棄用警告PHP 5.3+
32767E_ALL所有錯誤與警告PHP 5.3+ 值為 32767
關鍵限制:E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING 及部分 E_STRICT 無法被 set_error_handler() 捕獲。

三、錯誤處理四大層次

1. 最簡單:die()/exit()

$conn = mysqli_connect('localhost', 'user', 'pass', 'db')
    or die('資料庫連線失敗:' . mysqli_connect_error());
缺點:直接終止,無法統一格式、記錄日誌、優雅降級。

2. 自定義錯誤處理器:set_error_handler()

function customErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
    // 格式化輸出
    $msg = "[{$errno}] {$errstr} in {$errfile}:{$errline}";
    error_log($msg . "\n", 3, __DIR__ . '/logs/php_errors.log');
    // 開發環境顯示
    if (ini_get('display_errors')) {
        echo "
{$msg}
"; } // 不要對 E_RECOVERABLE_ERROR 返回 true,讓腳本繼續或拋出異常 return true; // 表示已處理,不再由內建處理器處理 } // 接管 E_ALL & ~E_STRICT(不含無法捕獲的類型) set_error_handler('customErrorHandler', E_ALL & ~E_STRICT);

3. 主動觸發錯誤:trigger_error()

if ($age < 0) {
    trigger_error("年齡不能為負數:{$age}", E_USER_WARNING);
}

4. 錯誤日誌記錄:error_log()

// 寫入系統日誌(syslog/event log)
error_log("資料庫連線失敗:{$err}", 0);

// 寫入自定義檔案
error_log("[" . date('c') . "] {$err}\n", 3, '/var/log/app/db_errors.log');

// 發送郵件給管理員
error_log("嚴重錯誤:{$err}", 1, 'admin@example.com', 'From: errors@example.com');

四、異常處理(Exception)

PHP 5 引入物件導向異常機制,適用於可預期、可恢復的業務邏輯錯誤。

基本結構

try {
    // 可能拋出異常的代碼
    $user = User::findById($id);
    if (!$user) {
        throw new Exception("用戶不存在:{$id}", 404);
    }
} catch (Exception $e) {
    // 捕獲並處理
    error_log($e->getMessage());
    // 回應使用者
    http_response_code($e->getCode() ?: 500);
    echo json_encode(['error' => $e->getMessage()]);
} finally {
    // 清理資源(關閉連線、釋放鎖)
    $db->close();
}

多重 catch 與異常重拋

try {
    // ...
} catch (ValidationException $e) {
    // 業務驗證失敗
    http_response_code(422);
    echo $e->getMessage();
} catch (DatabaseException $e) {
    // 資料庫錯誤,記錄詳細資訊後拋出通用異常
    error_log($e->getTraceAsString());
    throw new Exception('系統暫時無法使用,請稍後再試', 503);
} catch (Exception $e) {
    // 兜底
    error_log($e->getMessage());
    http_response_code(500);
    echo '伺服器內部錯誤';
}

自定義異常類別

class ValidationException extends Exception {}
class DatabaseException extends Exception {}
class NotFoundException extends Exception {}

設定全域異常處理器(捕獲未被 catch 的異常)

function globalExceptionHandler(Throwable $e) {
    http_response_code(500);
    error_log("[UNCAUGHT] {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}");
    if (ini_get('display_errors')) {
        echo "

系統錯誤

{$e->getMessage()}

"; } else { echo "

服務暫時不可用

請稍後再試

"; } } set_exception_handler('globalExceptionHandler');

五、最佳實踐總結

  1. 開發環境:display_errors=On、error_reporting=E_ALL、使用 set_error_handler + set_exception_handler 統一格式化輸出。
  2. 生產環境:display_errors=Off、log_errors=On、錯誤寫入檔案/系統日誌/ELK,關鍵錯誤發送告警(Email/Slack/DingTalk)。
  3. 業務邏輯錯誤:拋出具體異常類別(ValidationException 等),在控制器/中介層統一捕獲轉為標準 API 回應。
  4. 資源清理:善用 finally 或 register_shutdown_function 確保連線、鎖、臨時檔案釋放。
  5. 永不 直接 echo $e->getTraceAsString() 給使用者看。

建立一套專案統一的錯誤/異常處理骨架,能讓團隊專注於業務邏輯,同時保障系統可觀測性與安全性。

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