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

PHP 異常處理完整指南:拋出、捕獲特定類型、自定義異常、重新拋出、頂層處理器

     編輯:PHP 綜合知識

PHP 5 引入 OO 異常機制,取代傳統錯誤代碼/返回值檢查。本文系統講解 try-catch-finally、自定義異常類別、多重捕獲順序、重新拋出、set_exception_handler() 等核心技術,附執行流程圖解。

基礎語法

<?php
try {
    // 可能拋出異常的代碼
    $result = riskyOperation();
} catch (SpecificException $e) {
    // 捕獲特定異常
    handleSpecific($e);
} catch (Exception $e) {
    // 捕獲其他所有異常(父類型放最後)
    handleGeneric($e);
} finally {
    // PHP 5.5+,無論是否異常都執行(清理資源)
    cleanup();
}
?>

自定義異常類別

<?php
// 業務異常基類
class AppException extends Exception {}

// 具體業務異常
class HeavyParcelException extends AppException {}
class InvalidAddressException extends AppException {}
class PaymentFailedException extends AppException {}

// 可攜帶額外資料
class ApiException extends Exception {
    public function __construct(string $message, int $code, public array $context = []) {
        parent::__construct($message, $code);
    }
}
?>

實戰範例:快遞派送

<?php
class Parcel {
    public string $address = '';
    public float $weight = 0;
}

class Courier {
    public function ship(Parcel $parcel): bool {
        if (empty($parcel->address)) {
            throw new InvalidAddressException('地址未填寫');
        }
        if ($parcel->weight > 5) {
            throw new HeavyParcelException('包裹超過 5kg 限制');
        }
        return true;
    }
}

$courier = new Courier();
$parcel = new Parcel();
$parcel->weight = 7; // 故意超重

try {
    $courier->ship($parcel);
    echo "派送成功";
} catch (HeavyParcelException $e) {
    echo "重量異常: {$e->getMessage()}"; // 捕獲特定
    // 導向選擇其他快遞
} catch (InvalidAddressException $e) {
    echo "地址異常: {$e->getMessage()}";
    exit; // 終止後續流程
} catch (Exception $e) {
    echo "未知錯誤: {$e->getMessage()}";
}
echo "
程式繼續執行..."; ?>

執行流程圖解(關鍵)

  1. try 區塊執行 ship()。
  2. ship() 先檢查地址 → 拋出 InvalidAddressException。
  3. 依序匹配 catch:第一個 HeavyParcelException 不匹配 → 第二個 InvalidAddressException 匹配 → 執行該區塊。
  4. exit 終止腳本,finally(若有)仍會執行。

⚠️ 捕獲順序原則:子類在前,父類在後。若寫反,父類會「吞掉」子類異常。

進階技巧

1. 重新拋出異常

<?php
try {
    $pdo->beginTransaction();
    // ...
    $pdo->commit();
} catch (PDOException $e) {
    $pdo->rollBack();
    // 記錄日誌後重新拋出,讓上層決定如何處理
    error_log($e->getMessage());
    throw $e; // 或 throw new AppException('DB 錯誤', 0, $e);
}
?>

2. 異常鏈(PHP 7+)

<?php
try {
    // ...
} catch (Throwable $e) {
    throw new RuntimeException('處理失敗', 500, $e); // $e 成為 previous
}
// 上層可用 $e->getPrevious() 追溯根因
?>

3. 頂層異常處理器(最後防線)

<?php
set_exception_handler(function (Throwable $e) {
    // 記錄完整堆疊
    error_log("未捕獲異常: {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}");
    // 回傳友善錯誤頁(非 CLI)
    if (php_sapi_name() !== 'cli') {
        http_response_code(500);
        echo '系統繁忙,請稍後再試';
    }
});
?>

4. 將錯誤轉為異常

<?php
set_error_handler(function (int $severity, string $message, string $file, int $line) {
    if (!(error_reporting() & $severity)) return false; // 忽略 @ 抑制的錯誤
    throw new ErrorException($message, 0, $severity, $file, $line);
});
?>

Throwable 介面(PHP 7+)

Exception 和 Error 都實作 Throwable。catch (Throwable $e) 可同時捕獲異常與致命錯誤(TypeError、ParseError 等)。

最佳實踐清單

  • ✅ 異常類別命名以 Exception 結尾,繼承 Exception 或 AppException。
  • ✅ 只捕獲預期能處理的異常,不明確的往上拋。
  • ✅ finally 釋放資源(關閉連線、釋放鎖、清理暫存檔)。
  • ✅ 生產環境關閉 display_errors,啟用 log_errors + 頂層處理器。
  • ❌ 不要用異常控制正常流程(如迴圈結束、驗證失敗),改用返回值/狀態碼。

結語

異常處理的核心是關注點分離:業務邏輯專注「快樂路徑」,錯誤處理集中在 catch、頂層處理器。掌握捕獲順序、異常鏈、重新拋出,程式碼健壯度大幅提升。

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