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

PHP 5 異常處理機制深度解析與實戰範例

     編輯:PHP 相關知識

PHP 5 引入類似 Java/C++ 的物件導向異常處理模型,提供 try、catch、throw 關鍵字,讓錯誤流程控制更結構化、可維護。本文系統整理內建 Exception 類別結構、語法規則、多重捕獲與自訂異常最佳實務。

內建 Exception 類別核心成員

屬性/方法存取層級說明
$messageprotected異常訊息字串
$codeprotected使用者自訂錯誤代碼 (int)
$fileprotected拋出異常的檔案名稱
$lineprotected拋出異常的程式碼行號
__construct($msg, $code)public建構子,可選參數
getMessage()final public回傳異常訊息
getCode()final public回傳錯誤代碼
getFile()final public回傳檔案名稱
getLine()final public回傳行號
getTrace()final public回傳回溯陣列
getTraceAsString()final public回傳格式化回溯字串
__toString()public可覆寫,回傳字串表現

基本語法結構

<?php
// 1. try-catch 基本捕獲
try {
    // 高風險操作:資料庫連線、檔案讀寫、API 呼叫
    $db = new PDO($dsn, $user, $pass);
} catch (PDOException $e) {
    // 捕獲特定異常類別
    logError($e->getMessage());
    showFriendlyMessage("服務暫時不可用,請稍後再試");
}

// 2. throw 主動拋出異常
function divide($a, $b) {
    if ($b == 0) {
        throw new Exception("除數不可為零", 1001); // 自訂代碼
    }
    return $a / $b;
}

try {
    echo divide(10, 0);
} catch (Exception $e) {
    echo "錯誤代碼: {$e->getCode()}"; // 1001
    echo "錯誤訊息: {$e->getMessage()}"; // 除數不可為零
}

// 3. 多重 catch:依類別精準處理
try {
    $pdo = new PDO($dsn, $user, $pass);
    $stmt = $pdo->query("SELECT * FROM users");
} catch (PDOException $e) {
    // 資料庫專屬錯誤
    handleDbError($e);
} catch (Exception $e) {
    // 其他通用錯誤
    handleGenericError($e);
}

// 4. finally (PHP 5.5+):無論是否異常必執行
$fp = fopen("data.txt", "r");
try {
    $data = fread($fp, filesize("data.txt"));
} finally {
    fclose($fp); // 保證資源釋放
}
?>

實戰範例:資料庫操作與業務邏輯異常分層

<?php
// 自訂異常階層
class AppException extends Exception {}
class ValidationException extends AppException {}
class NotFoundException extends AppException {}
class DatabaseException extends AppException {}

// Service 層
class UserService {
    private $pdo;
    
    public function __construct(PDO $pdo) { $this->pdo = $pdo; }
    
    public function register(string $email, string $password): int {
        // 業務驗證拋出 ValidationException
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new ValidationException("Email 格式錯誤", 2001);
        }
        if (strlen($password) < 8) {
            throw new ValidationException("密碼長度至少 8 碼", 2002);
        }
        
        try {
            $stmt = $this->pdo->prepare("INSERT INTO users (email, password_hash) VALUES (?, ?)");
            $stmt->execute([$email, password_hash($password, PASSWORD_DEFAULT)]);
            return (int)$this->pdo->lastInsertId();
        } catch (PDOException $e) {
            // 封裝底層異常,拋出上層可理解的 DatabaseException
            if ($e->getCode() == 23000) { // SQLSTATE 唯一鍵衝突
                throw new ValidationException("Email 已被註冊", 2003);
            }
            throw new DatabaseException("資料庫錯誤: " . $e->getMessage(), 5001, $e);
        }
    }
}

// Controller 層
try {
    $userId = (new UserService($pdo))->register($_POST['email'], $_POST['password']);
    jsonResponse(['success' => true, 'user_id' => $userId]);
} catch (ValidationException $e) {
    jsonResponse(['success' => false, 'code' => $e->getCode(), 'msg' => $e->getMessage()], 400);
} catch (DatabaseException $e) {
    error_log($e->getTraceAsString()); // 記錄完整堆疊
    jsonResponse(['success' => false, 'msg' => '系統繁忙,請稍後再試'], 500);
} catch (Exception $e) {
    error_log("未預期錯誤: " . $e->getMessage());
    jsonResponse(['success' => false, 'msg' => '未知錯誤'], 500);
}
?>

進階技巧與最佳實務

  • 異常轉換:底層捕獲具體異常(如 PDOException),拋出領域相關異常(DatabaseException),隱藏實作細節,符合「依賴倒置原則」。
  • 全域異常處理器:set_exception_handler(function($e) { ... }) 捕獲未被 catch 的異常,統一記錄日誌、顯示友善錯誤頁,避免暴露堆疊資訊。
  • 錯誤代碼體系:建立專案統一錯誤代碼對照表(如 1xxx=系統、2xxx=驗證、3xxx=業務、4xxx=第三方、5xxx=資料庫),前後端對接更高效。
  • 避免濫用:異常僅用於「異常狀況」(不可預期、不可直接處理),一般業務流程控制(如查無資料回傳 null/false)勿用異常,效能較佳且語意清晰。
  • SPL 內建異常:善用 InvalidArgumentException、OutOfRangeException、RuntimeException 等標準異常,減少自訂類別數量。

總結

PHP 異常處理機制讓錯誤流程可控、可追蹤、可分層。善用 try-catch-finally 結構、自訂異常階層與全域處理器,能顯著提升程式碼健壯度與維護性。記住核心原則:拋出具體異常、捕獲精確類別、封裝底層細節、統一錯誤回應。

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