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

PHP 捕獲致命錯誤與執行逾時的正確姿勢

     編輯:PHP 相關知識

PHP 捕獲致命錯誤與執行逾時的正確姿勢

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']}");
    }
});
?>

常見誤區避坑

  1. 誤以為 try-catch 能捕獲逾時:Fatal Error 不是 Exception,try-catch 捕獲不到
  2. 誤用 sleep 測試逾時:sleep() 不計入執行時間,需用忙等待 while(true) 或大量計算
  3. 關閉函數中輸出內容:若腳本已輸出 HTTP Header,關閉函數再輸出會導致 Headers already sent 警告
  4. 重複註冊:多次 register_shutdown_function 會依序執行,注意順序依賴

生產環境部署建議

  • 整合 Monolog + Sentry/Rollbar 自動上報錯誤堆疊
  • 區分 display_errors = Off、log_errors = On、error_log = /var/log/php/error.log
  • Nginx/PHP-FPM 層面設定 request_terminate_timeout 防止 Worker 持續佔用
  • 健康檢查端點回傳最近錯誤率,配合 Kubernetes Liveness Probe 自動重啟

掌握 register_shutdown_function + error_get_last() 組合,是 PHP 應用實現優雅錯誤處理、自動化監控告警的基石技能。

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