2010-12-10 17 views
31

根據the comment on this answer有可能通過shutdown function捕獲致命錯誤,使用set_error_handler()無法捕獲。使用register_shutdown_function()處理PHP中的致命錯誤

但是,我找不到如何確定是否由於致命錯誤或由於腳本到達結束而導致關閉。

此外,調試回溯函數似乎在關閉函數中已不存在,使得將堆棧跟蹤記錄到發生致命錯誤的地方非常沒有價值。

所以我的問題是:什麼是對致命錯誤(尤其是未定義函數調用)做出反應的最佳方式,同時保持創建正確回溯的能力?

回答

54

這個工作對我來說:

function shutdown() { 
    $error = error_get_last(); 
    if ($error['type'] === E_ERROR) { 
     // fatal error has occured 
    } 
} 

register_shutdown_function('shutdown'); 

spl_autoload_register('foo'); 
// throws a LogicException which is not caught, so triggers a E_ERROR 

不過,你可能已經知道了,但只是爲了確保:你不能以任何方式E_ERROR恢復。

至於回溯,你不能...... :(在大多數情況下,一個致命的錯誤,尤其是未定義的函數錯誤,你並不真的需要它。查找它發生的文件/行是在這種情況下回溯是無關緊要的

+0

GREAT SNIPPET!我也使用'echo'錯誤MSG:[「。$ error ['message']。」] on line:[「。$ error ['line']。」] \ r \ n「;'UPVOTED:) – 2017-06-24 00:56:44

7

通過register_shutdown_function區分致命錯誤和正確應用程序關閉的一種方法是將常量定義爲程序的最後一行,然後檢查常量是否已定義:

function fatal_error() { 
if (! defined(PROGRAM_EXECUTION_SUCCESSFUL)) { 
     // fatal error has occurred 
    } 
} 

register_shutdown_function('fatal_error'); 

define('PROGRAM_EXECUTION_SUCCESSFUL', true); 

如果程序到達最後,它可能會沒有遇到致命錯誤,所以我們知道如果定義了常量不運行該函數。

error_get_last()是一個數組,其中包含有關應該需要調試的致命錯誤的所有信息,儘管它不會像前面提到的那樣有回溯。

通常,如果您的php程序遇到致命錯誤(而不是異常),您希望程序炸燬以便您可以找到並修復問題。我發現register_shutdown_function對於想要關閉錯誤報告的生產環境很有用,但希望以某種方式在後臺記錄錯誤,以便您可以對錯誤進行響應。如果出現這種錯誤,您也可以使用該功能將用戶引導至友好的HTML頁面,以便您不只是提供空白頁面。

4

只是一個好的技巧,以獲得當前error_handler方法=)

<?php 
register_shutdown_function('__fatalHandler'); 
function __fatalHandler() 
{ 
    $error  = error_get_last(); 

    //check if it's a core/fatal error, otherwise it's a normal shutdown 
    if($error !== NULL && $error['type'] === E_ERROR) { 
     //Bit hackish, but the set_exception_handler will return the old handler 
     function fakeHandler() { } 
     $handler = set_exception_handler('fakeHandler'); 
     restore_exception_handler(); 
     if($handler !== null) { 
      call_user_func($handler, new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line'])); 
     } 
     exit; 
    } 
} 
?> 

而且我wan't要注意,如果你調用

<?php 
ini_set('display_errors', false); 
?> 

腓停止顯示錯誤,否則錯誤文本將在您的錯誤處理程序之前發送給客戶端

-1

我對此使用「ob_start」。

function fatal_error_handler($buffer) { 
    if (preg_match("|(Fatal error:)(.+)|", $buffer, $regs)) { 
     //Your code 
    } 
    return $buffer; 
} 
ob_start("fatal_error_handler"); 
+0

This提示參數被傳遞,但使用正則表達式是一種效率較低的檢查方法。被接受的答案既清晰又高效。 – pcnate 2017-01-19 16:50:34