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

PHP 異常處理機制深度解析:Exception 類體系、自定義異常與最佳實踐

     編輯:PHP 相關知識

PHP 異常處理機制深度解析:Exception 類體系、自定義異常與最佳實踐

PHP 5 引入面向對象異常模型,取代傳統 trigger_error,提供結構化錯誤流控制。本文系統講解 Exception 體系、try-catch-finally 流程、自定義異常、多異常捕獲、重新拋出、頂層處理器,並給出生產級異常處理策略。

1. 異常基礎流程

<?php
function checkNum($num) {
    if ($num > 1) {
        throw new Exception("Value must be 1 or below");
    }
    return true;
}

try {
    checkNum(2);
    echo '不會執行';
} catch (Exception $e) {
    echo 'Message: ' . $e->getMessage(); // 輸出: Value must be 1 or below
}
// 程式繼續向下執行
  • throw:拋出異常對象,後續代碼停止執行。
  • try:包裹可能拋出異常的代碼塊。
  • catch:捕獲指定類型異常,接收 Exception $e 對象。
  • 若無匹配 catch 且未設頂層處理器 → Fatal Error: Uncaught Exception。

2. Exception 內置屬性與方法

3. 自定義異常類:擴展業務語義

class AppException extends Exception {
    // 可新增業務屬性
    protected $errorCode;
    public function __construct($message, $code = 0, $previous = null) {
        parent::__construct($message, $code, $previous);
        $this->errorCode = $code;
    }
    public function getErrorCode() { return $this->errorCode; }
    // 友好輸出
    public function __toString() {
        return __CLASS__ . ": [{$this->code}]: {$this->message}\n" . $this->getTraceAsString();
    }
}

// 使用
try {
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new AppException("Invalid email: $email", 1001);
    }
} catch (AppException $e) {
    logError($e->getErrorCode(), $e->getMessage());
}

好處:業務碼統一、便於日誌分類、API 直接返回結構化錯誤碼。

4. 多異常捕獲與捕獲順序

try {
    // 可能拋出 AppException、PDOException、TypeError 等
    $pdo->query($sql);
    validateInput($input);
} catch (AppException $e) {       // 先捕獲具體業務異常
    handleBizError($e);
} catch (PDOException $e) {       // 再捕獲數據庫異常
    handleDbError($e);
} catch (Throwable $e) {          // 最後捕獲所有剩餘 (PHP 7+)
    handleUnknownError($e);
}
  • 子類異常必須寫在父類之前,否則被父類攔截。
  • PHP 7 起 Throwable 為頂層接口,涵蓋 Exception 和 Error。

5. 重新拋出異常:轉換/豐富上下文

try {
    $pdo->query($sql);
} catch (PDOException $e) {
    // 記錄底層錯誤,拋出業務異常
    error_log("DB Error: " . $e->getMessage());
    throw new AppException("數據庫操作失敗", 500, $e); // $e 作為 previous 保留鏈
}

調用方捕獲 AppException 即可,無需知曉 PDO 細節,實現分層解耦。

6. 頂層異常處理器:最後防線

function globalExceptionHandler(Throwable $e) {
    // 記錄完整堆疊
    error_log("Uncaught: " . $e->getTraceAsString());
    // 用戶友好頁面
    if (php_sapi_name() !== 'cli') {
        http_response_code(500);
        include __DIR__ . '/templates/500.html';
    }
}
set_exception_handler('globalExceptionHandler');

// 測試
throw new Exception('測試頂層處理'); // 會觸發 globalExceptionHandler

適用於框架入口、CLI 腳本、API 統一錯誤輸出。

7. PHP 7+ 新特性:Throwable、TypeError、ArgumentCountError

  • Throwable:統一接口,catch 所有可拋出對象。
  • TypeError:類型聲明不匹配(嚴格模式)。
  • ArgumentCountError:參數數量錯誤。
  • DivisionByZeroError、ParseError、AssertionError 等內置 Error 類。

8. 生產級異常處理策略清單

  1. 分層定義:DomainException(業務邏輯)、InfrastructureException(外部依賴)、PresentationException(控制器/視圖)。
  2. 統一響應格式:API 返回 {code, message, data, trace_id},由中間件捕獲異常轉換。
  3. 日誌分級:ERROR 記錄業務異常+堆疊,CRITICAL 記錄基礎設施異常並告警。
  4. 不吞沒異常:catch 後必須處理(記錄/轉換/重拋),禁止空 catch。
  5. 資源清理用 finally:關閉連接、釋放鎖、刷新緩衝區。
  6. 測試覆蓋:單元測試驗證異常拋出條件、類型、消息、代碼。

總結

異常不是「錯誤」,而是「預期外但可控的流程分支」。善用 try-catch-finally、自定義異常體系、頂層處理器,能將錯誤處理從「到處判斷返回碼」轉變為「集中、結構化、可維護」的工程實踐。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
屬性/方法說明
getMessage()異常消息字串
getCode()異常代碼(int)
getFile()拋出文件路徑
getLine()拋出行號
getTrace()回溯數組
getTraceAsString()格式化回溯字串
__toString()完整描述(含堆疊)