register_shutdown_function的作用是在PHP 腳本執行結束時註冊一個回調函數,該函數在腳本終止時被調用。它常用於記錄致命錯誤、釋放資源或做一些後處理工作。
register_shutdown_function(function () {
$error = error_get_last();
if ($error !== null) {
// 錯誤處理邏輯
file_put_contents('/tmp/php_error.log', print_r($error, true));
}
});
register_shutdown_function能夠捕獲到的錯誤,通常是腳本終止前記錄在error_get_last()中的“致命錯誤”。常見可以被捕獲的錯誤類型包括:
E_ERROR :運行時致命錯誤
E_PARSE :解析錯誤(某些情況下)
E_CORE_ERROR 、 E_COMPILE_ERROR :PHP 啟動時的致命錯誤
E_USER_ERROR :用戶自定義的致命錯誤
這些錯誤通常會導致腳本中斷,在這種情況下,shutdown 函數才有機會運行,並通過error_get_last()捕獲錯誤詳情。
儘管register_shutdown_function很強大,但它並非無所不能。以下幾類錯誤或情形,它是無法捕獲的:
非致命錯誤不會導致腳本中斷,因此不會觸發register_shutdown_function中的錯誤處理邏輯:
echo $undefined_variable; // 報 notice,不影響執行
雖然shutdown函數會被調用,但error_get_last()返回的內容不會包含這些非致命錯誤。
如果腳本是通過exit或die主動退出的,而且沒有在退出前拋出致命錯誤,那麼error_get_last()返回值為null :
exit("退出程序"); // 觸發 shutdown,但無錯誤記錄
有些語法錯誤發生在PHP 解析階段,腳本甚至不會進入執行流程,這意味著register_shutdown_function根本沒有機會註冊:
// 以下代碼直接導致解析失敗,無法註冊 shutdown 函數
echo "Hello
雖然不是“錯誤無法捕獲”,但需要特別注意的是,如果發生致命錯誤前未使用ob_start()開啟輸出緩衝,頁面的輸出可能會丟失,導致看不到任何錯誤提示。這種情況常被誤以為“shutdown 函數無效”。
錯誤抑制符不會阻止致命錯誤,但會抑制非致命錯誤的顯示,容易造成混淆。 register_shutdown_function能捕獲致命錯誤,即使使用了@ :
@trigger_error("This is a user warning", E_USER_WARNING); // 不會捕獲
如前所述, register_shutdown_function只能處理致命錯誤,不能作為通用的錯誤處理機制。對於E_WARNING 、 E_NOTICE應使用set_error_handler 。
錯誤處理應多層次防禦。最佳實踐是結合使用:
set_error_handler()捕獲警告、通知等非致命錯誤;
set_exception_handler()捕獲未捕捉的異常;
register_shutdown_function()捕獲腳本終止前最後一次錯誤。
很多時候, shutdown的確被執行了,但由於error_get_last()返回null ,什麼都沒記錄,開發者誤以為函數沒起作用。
為了更全面的錯誤處理體系,推薦如下組合:
set_error_handler('customErrorHandler');
set_exception_handler('customExceptionHandler');
register_shutdown_function('shutdownHandler');
function customErrorHandler($errno, $errstr, $errfile, $errline) {
// 記錄 warning、notice 等
}
function customExceptionHandler($exception) {
// 記錄未捕获异常
}
function shutdownHandler() {
$error = error_get_last();
if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
// 致命错误記錄
file_get_contents('https://gitbox.net/log.php?msg=' . urlencode($error['message']));
}
}