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

PHP 5/7/8 異常處理機制完整教學

     編輯:PHP 相關知識

PHP 異常處理核心概念

PHP 5 引入物件導向異常模型,PHP 7 擴展為 Throwable 介面統一 Exception 與 Error,PHP 8 增強語法彈性。掌握完整體系是編寫健壯程式的基礎。

異常類別繼承圖

Throwable (介面, PHP 7+)
├── Exception (使用者程式異常)
│   ├── LogicException (邏輯錯誤)
│   │   ├── InvalidArgumentException
│   │   ├── LengthException
│   │   └── DomainException
│   ├── RuntimeException (執行期錯誤)
│   │   ├── OutOfBoundsException
│   │   ├── OverflowException
│   │   └── UnexpectedValueException
│   └── ... (其他 SPL 異常)
└── Error (引擎內部錯誤, PHP 7+)
    ├── TypeError (型別錯誤)
    ├── ArgumentCountError (參數數量錯誤)
    ├── ArithmeticError (數學錯誤)
    │   └── DivisionByZeroError
    ├── AssertionError (斷言失敗)
    └── ParseError (解析錯誤)

基本語法結構

<?php
try {
    // 可能拋出異常的程式碼
    $result = riskyOperation($input);
} catch (SpecificException $e) {
    // 處理特定異常
    handleSpecific($e);
} catch (AnotherException $e) {
    // 處理另一類異常
} catch (Throwable $e) {
    // 捕獲所有 Exception 與 Error (PHP 7+)
    // 建議僅用於最外層或日誌記錄
} finally {
    // 無論是否發生異常都會執行
    // 適用於資源清理:關閉連線、釋放鎖、關閉檔案
    cleanup();
}
?>

異常物件核心屬性與方法

屬性/方法說明範例輸出
getMessage()異常訊息"Division by zero"
getCode()自定義錯誤碼404
getFile()發生異常的檔案路徑"/var/www/app/Service.php"
getLine()發生異常的行號42
getTrace()堆疊追蹤陣列[['file'=>..., 'line'=>..., 'function'=>...], ...]
getTraceAsString()格式化堆疊字串"#0 /app/Service.php(42): ...\n#1 ..."
getPrevious()前一個異常 (鏈式)Exception 物件或 null
__toString()完整字串表示"Exception: Division by zero in ..."

進階技巧與最佳實踐

1. 異常鏈

<?php
try {
    $pdo->query($sql);
} catch (PDOException $e) {
    // 保留原始異常資訊,拋出業務層異常
    throw new DatabaseException('查詢失敗', 0, $e);
}
?>

2. 多重捕獲 (PHP 7.1+)

<?php
try {
    // ...
} catch (ValidationException | AuthenticationException $e) {
    // 同樣處理邏輯的異常可合併
    http_response_code(400);
    logError($e);
}
?>

3. 條件捕獲 (PHP 8.0+)

<?php
try {
    // ...
} catch (DatabaseException $e) if ($e->getCode() === 1205) {
    // 僅捕獲鎖等待超時 (MySQL 錯誤碼 1205)
    retryOperation();
} catch (DatabaseException $e) {
    // 其他資料庫錯誤
}
?>

4. 全域異常處理器

<?php
set_exception_handler(function (Throwable $e) {
    http_response_code(500);
    logError($e);
    echo json_encode([
        'error' => 'Internal Server Error',
        'trace_id' => uniqid()
    ]);
});

// 注意:全域處理器無法捕獲:
// - E_ERROR / E_PARSE / E_CORE_ERROR 等致命錯誤 (需 register_shutdown_function)
// - 異常處理器內部拋出的異常

5. 致命錯誤捕獲 (Shutdown Function)

<?php
register_shutdown_function(function () {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        // 將致命錯誤轉為異常處理
        $e = new ErrorException(
            $error['message'],
            0,
            $error['type'],
            $error['file'],
            $error['line']
        );
        // 交給全域處理器或直接處理
        handleFatalError($e);
    }
});
?>

常見錯誤與避坑指南

錯誤做法問題正確做法
catch (Exception $e) { }吞沒異常,導致 Bug 難以追蹤至少記錄日誌,或重拋 throw $e
用異常控制正常流程效能差、語意不清預期情況用回傳值/Optional/Result 物件
catch 後不處理直接結束資源洩漏 (連線、檔案、鎖)使用 finally 或 RAII 模式清理
拋出新異常未保留前因丟失根因堆疊throw new NewException(msg, code, $previous)

PHP 8 新特性總覽

  • throw 運算式化:$x = $arr[$key] ?? throw new NotFoundException();
  • catch 可省略變數:catch (InvalidArgumentException) { ... }
  • 內建 ValueError、UnhandledMatchError
  • Stringable 介面支援 __toString() 型別提示

異常處理不是錯誤的終點,而是程式韌性的起點。建立分層、分類、可追蹤的異常體系,配合統一的處理策略,能讓專案在面對不可預期情況時優雅降級、快速定位、持續演進。

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