PHP 5 引入物件導向異常模型,try-catch 取代傳統錯誤碼檢查,讓錯誤處理更結構化。本文從語法到進階模式完整說明。
<?php
try {
// 可能拋出異常的程式碼
$result = riskyOperation();
} catch (Exception $e) {
// 捕獲 Exception 及其子類
logError($e->getMessage());
showFriendlyMessage('系統繁忙,請稍後再試');
} finally { // PHP 5.5+
// 無論是否異常都會執行 (關閉連線、釋放鎖)
cleanup();
}
throw 拋出後,當前 try 區塊立即中止,跳往匹配的 catch。catch,可多個捕獲不同型別 (子類優先)。catch 且未設定 set_exception_handler(),致命錯誤 Uncaught Exception。catch 區塊可再次 throw (重新拋出或包裝新異常)。<?php
class MyException extends Exception {
public function __construct($message, $code = 0) {
parent::__construct($message, $code);
}
public function __toString() {
return __CLASS__ . ":[{$this->code}]:{$this->message}";
}
public function customHandler() { echo "自訂處理: {$this->message}"; }
}
class Service {
public function doAction($mode) {
switch ($mode) {
case 1: throw new MyException('模式1錯誤', 1001);
case 2: throw new InvalidArgumentException('模式2參數錯誤');
default: return 'OK';
}
}
}
try {
$svc = new Service();
echo $svc->doAction(1);
} catch (MyException $e) {
echo "捕獲自訂異常: $e";
$e->customHandler();
} catch (Exception $e) {
echo "捕獲標準異常: {$e->getMessage()}";
}
<?php
// 錯誤示範:require 失敗不拋出 Exception,只產生 Warning
try {
require 'missing.php'; // 不會進入 catch
} catch (Exception $e) { }
// 正確做法:手動檢查並拋出
try {
$file = 'config.php';
if (!file_exists($file)) {
throw new RuntimeException("配置檔不存在: $file");
}
require $file;
} catch (Exception $e) {
error_log($e->getMessage());
die('系統初始化失敗');
}
try {
$pdo->query($sql);
} catch (PDOException $e) {
throw new RepositoryException('資料庫查詢失敗', 0, $e); // 第三參數 previous
}
set_exception_handler(function (Throwable $e) {
http_response_code(500);
logError($e);
echo json_encode(['error' => 'Internal Server Error']);
// 生產環境不輸出堆疊
});
Throwable (PHP 7+)try { ... } catch (Throwable $e) { // 捕獲 Exception + Error
// 統一處理所有可拋出物件
}
try-catch (如 API 呼叫失敗、檔案不存在)。Exception,命名以 XxxException 結尾,方便分類捕獲。finally 用於資源釋放 (關閉檔案、資料庫連線、釋放鎖)。if 判斷即可)。$e->getTraceAsString() 完整堆疊。