異常處理是現代 PHP 編寫健壯代碼的基石。本文從基礎語法切入,說明 try/throw/catch 機制、自訂異常類別、多重捕獲、finally 區塊與最佳實務。
throw new Exception($message, $code))。<?php
function checkNumber(int $number): bool {
if ($number > 1) {
throw new Exception("數值必須 ≤ 1", 400); // 拋出異常
}
return true;
}
try {
checkNumber(2); // 觸發異常
echo "檢查通過\n"; // 不會執行
} catch (Exception $e) {
echo "捕獲異常: {$e->getMessage()} (代碼: {$e->getCode()})\n";
// 輸出: 捕獲異常: 數值必須 ≤ 1 (代碼: 400)
} finally {
echo "finally 區塊總是執行\n";
}
?>
| 方法 | 說明 |
|---|---|
getMessage() | 異常訊息字串 |
getCode() | 異常代碼 (int) |
getFile() | 拋出異常的檔案路徑 |
getLine() | 拋出異常的行號 |
getTrace() | 堆疊追蹤陣列 |
getTraceAsString() | 格式化堆疊字串 |
getPrevious() | 前一個異常 (巢狀異常) |
<?php
class ValidationException extends Exception {}
class DatabaseException extends Exception {}
function process(array $data) {
if (empty($data['email'])) throw new ValidationException('Email 必填');
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) throw new ValidationException('Email 格式錯誤');
// 模擬資料庫錯誤
if ($data['email'] === 'fail@db.com') throw new DatabaseException('連線失敗');
return true;
}
try {
process(['email' => 'invalid']);
} catch (ValidationException $e) {
echo "驗證錯誤: {$e->getMessage()}\n";
} catch (DatabaseException $e) {
echo "資料庫錯誤: {$e->getMessage()}\n";
} catch (Exception $e) {
echo "其他錯誤: {$e->getMessage()}\n"; // 捕獲所有其他 Exception 子類
}
?>
規則:catch 依序匹配,子類別必須寫在父類別之前。
<?php
abstract class AppException extends Exception {
protected int $httpCode = 500;
public function getHttpCode(): int { return $this->httpCode; }
}
class NotFoundException extends AppException {
protected int $httpCode = 404;
public function __construct(string $resource = 'Resource') {
parent::__construct("{$resource} 不存在", 404);
}
}
class UnauthorizedException extends AppException {
protected int $httpCode = 401;
}
?>
好處:統一錯誤碼、HTTP 狀態碼映射、方便全域異常處理器識別類型。
<?php
set_exception_handler(function (Throwable $e) {
// 記錄日誌
error_log("Uncaught: {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}");
// 根據環境決定輸出
if (ini_get('display_errors')) {
echo "<pre>{$e->getTraceAsString()}</pre>";
} else {
http_response_code($e instanceof AppException ? $e->getHttpCode() : 500);
echo json_encode(['error' => $e->getMessage()]);
}
});
// 也可捕獲 Fatal Error (PHP 7+)
register_shutdown_function(function () {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
throw new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']);
}
});
?>
PHP 7 引入 Throwable 介面,Exception 與 Error 皆實作之。catch (Throwable $e) 可同時捕獲例外與錯誤 (如 TypeError, ParseError)。
if/else。catch (Exception $e) {} 空白處理會隱藏 Bug,至少記錄日誌。set_exception_handler。finally 關閉連線、釋放鎖、清理暫存檔。<?php
function apiResponse($data = null, string $message = '', int $code = 200): void {
http_response_code($code);
header('Content-Type: application/json');
echo json_encode(compact('code', 'message', 'data'), JSON_UNESCAPED_UNICODE);
exit;
}
try {
$user = UserService::getById($_GET['id'] ?? 0);
if (!$user) throw new NotFoundException('用戶');
apiResponse($user);
} catch (NotFoundException $e) {
apiResponse(null, $e->getMessage(), $e->getHttpCode());
} catch (ValidationException $e) {
apiResponse(null, $e->getMessage(), 422);
} catch (Throwable $e) {
apiResponse(null, '伺服器內部錯誤', 500);
}
?>
掌握異常處理機制,能讓你的 PHP 代碼更清晰、可維護、易於除錯。建立專案專屬的異常體系與全域處理器,是專業框架開發的標配。