在 PHP 中,頂層異常處理器 是當程式碼拋出異常但未被任何 try-catch 區塊捕獲時,最後的防線。透過 set_exception_handler() 註冊自訂函式,可統一記錄錯誤日誌、顯示友善錯誤頁面,避免暴露敏感堆疊資訊。
Fatal error: Uncaught Exception... 並終止腳本。set_exception_handler('myHandler');,處理器函式需接受一個 Exception 物件參數。<?php
// 註冊頂層異常處理器
set_exception_handler('myTopHandler');
function myTopHandler($exception) {
// 實務上應記錄至日誌檔,而非直接 echo
echo "【頂層處理器捕獲】代碼:{$exception->getCode()} | 訊息:{$exception->getMessage()} | 檔案:{$exception->getFile()} 第 {$exception->getLine()} 行";
}
// 測試:拋出未被捕獲的異常
throw new Exception("這是一個刻意拋出的測試異常", 1001);
?>
<?php
set_exception_handler('globalHandler');
function globalHandler($e) {
error_log("[GLOBAL] " . $e->getMessage()); // 寫入錯誤日誌
http_response_code(500);
include __DIR__ . '/templates/500.php'; // 顯示友善錯誤頁
exit;
}
function riskyOperation($input) {
if ($input === 'hello') {
throw new Exception("禁止輸入 'hello'", 400);
}
return "處理成功:" . $input;
}
try {
// 假設這裡呼叫深層函式庫,可能拋出各種異常
echo riskyOperation("hello"); // 觸發異常
} catch (Exception $e) {
// 區域性處理:記錄、轉型、或判斷是否需重新拋出
if ($e->getCode() === 400) {
// 業務邏輯錯誤,直接顯示給使用者
echo "操作失敗:" . $e->getMessage();
} else {
// 系統級錯誤,拋給頂層處理器統一處理
throw $e;
}
}
?>
PHP 早期版本的錯誤(如 Warning、Notice、除以零)不會拋出 Exception,而是觸發傳統錯誤處理機制。因此:
<?php
try {
$result = 10 / 0; // 產生 Warning,非 Exception
} catch (Exception $e) {
echo "永遠不會執行到這裡";
}
// 輸出:Warning: Division by zero ...
?>
解決方案:PHP 7+ 可用 set_error_handler() 將錯誤轉為 ErrorException;或直接升級至 PHP 7/8,大多數嚴重錯誤已改為拋出 Error(實作 Throwable 介面),可統一捕獲。
catch 處理,後者拋給頂層。register_shutdown_function() 捕獲致命錯誤(PHP 7 前)。