set_error_handler() 無法捕獲 E_ERROR 等致命錯誤,超時屬於致命錯誤。唯一可靠方案是註冊關閉函數,在腳本終止前檢查 error_get_last()。
ini_set('max_execution_time', 1); // 1 秒超時,演示用
function shutdown() {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE])) {
// 記錄日誌、發送告警、優雅降級
error_log("FATAL: {$error['message']} in {$error['file']}:{$error['line']}");
// 可選:發送郵件/Slack/釘釘通知
}
}
register_shutdown_function('shutdown');
// 模擬長時間運行
while (true) {
// sleep() 不計入 max_execution_time
// usleep() 計入
usleep(100000);
}
usleep() 或真實計算測試。return 繼續主流程。class FatalErrorHandler {
public static function register(callable $handler) {
register_shutdown_function(function () use ($handler) {
$error = error_get_last();
if ($error && self::isFatal($error['type'])) {
$handler($error);
}
});
}
private static function isFatal(int $type): bool {
return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]);
}
}
// 使用
FatalErrorHandler::register(function ($error) {
// 發送到 Sentry/日誌中心
\Log::channel('fatal')->error($error['message'], $error);
});
這是 PHP 運行時層面唯一能「感知」致命錯誤的鉤子,務必在項目啟動階段 (bootstrap) 註冊。