set_error_handler() 無法捕獲 E_ERROR、E_PARSE、E_CORE_ERROR 等致命錯誤,也無法捕獲 max_execution_time 觸發的 Fatal Error。正確方案是註冊 register_shutdown_function(),在腳本結束階段(含致命錯誤中止)檢查 error_get_last()。
<?php
// 設定 1 秒執行限制(測試用)
ini_set('max_execution_time', 1);
function shutdownHandler() {
// 取得最後一個錯誤(含致命錯誤)
$error = error_get_last();
if ($error !== null) {
// 依錯誤類型分類處理
switch ($error['type']) {
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_PARSE:
// 致命錯誤:記錄、告警、優雅降級
error_log("[FATAL] {$error['message']} in {$error['file']}:{$error['line']}");
// 可在此發送郵件/Slack/钉钉告警
break;
case E_WARNING:
case E_NOTICE:
case E_DEPRECATED:
// 非致命:視業務決定是否記錄
break;
}
}
// 正常結束也會觸發,可做清理/統計
// echo "Script shutdown.\n";
}
register_shutdown_function('shutdownHandler');
// 模擬無限迴圈觸發逾時
while (true) {
// 故意不 sleep,佔用 CPU 觸發 max_execution_time
}
?>
| 項目 | 說明 |
|---|---|
register_shutdown_function | 腳本結束前保證執行(含 die/exit、致命錯誤、逾時) |
error_get_last() | 取得最後發生的錯誤陣列:['type', 'message', 'file', 'line'] |
max_execution_time | 僅計算 CPU 時間,sleep()/usleep()/資料庫查詢/網路 IO 不計入 |
| 輸出緩衝 | 關閉函數執行時輸出緩衝仍開啟,可用 ob_get_clean() 取得已輸出內容 |
<?php
// 1. 設定自定義例外處理器(捕獲未捕獲的 Exception/Throwable)
set_exception_handler(function (Throwable $e) {
error_log("[UNCAUGHT EXCEPTION] {$e->getMessage()}\n{$e->getTraceAsString()}");
// 生產環境:顯示友善錯誤頁、記錄追蹤 ID
echo "系統暫時無法處理請求,請稍後再試。";
});
// 2. 設定錯誤處理器(將錯誤轉為 Exception,統一走 exception_handler)
set_error_handler(function ($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) return false; // 忽略被 @ 抑制的錯誤
throw new ErrorException($message, 0, $severity, $file, $line);
});
// 3. 關閉函數統一收口
register_shutdown_function(function () {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE])) {
// 致命錯誤無法轉 Exception,這裡手動處理
error_log("[SHUTDOWN FATAL] {$error['message']} in {$error['file']}:{$error['line']}");
}
});
?>
sleep() 不計入執行時間,需用忙等待 while(true) 或大量計算Headers already sent 警告register_shutdown_function 會依序執行,注意順序依賴display_errors = Off、log_errors = On、error_log = /var/log/php/error.logrequest_terminate_timeout 防止 Worker 持續佔用掌握 register_shutdown_function + error_get_last() 組合,是 PHP 應用實現優雅錯誤處理、自動化監控告警的基石技能。