默認情況下,PHP 腳本發生錯誤(如調用未定義函數)會直接在頁面輸出 Fatal error: Call to undefined function... 並終止執行。這不僅嚇壞用戶,還暴露了服務器路徑、代碼結構等敏感信息,構成安全隱患。PHP 提供了 set_error_handler() 機制,允許開發者攔截錯誤、記錄日誌、返回友好提示,甚至忽略特定錯誤繼續執行。
PHP 將錯誤分為三大類(由低到高):
include() 失敗,腳本繼續執行。這些錯誤可在啟動、解析、編譯、運行階段發生。常用常量包括 E_NOTICE、E_WARNING、E_ERROR、E_ALL 等。
error_reporting() 決定哪些錯誤會被顯示(而非是否發生)。三個典型示例:
<?php
error_reporting(E_WARNING | E_ERROR);
echo $undefinedVar; // Notice,不顯示
callUndefFunc(); // Fatal Error,顯示並終止
?>
<?php
error_reporting(0);
echo $undefinedVar; // 無輸出
callUndefFunc(); // 終止但無任何提示,用戶看到空白頁
?>
<?php
error_reporting(E_ALL);
echo $undefinedVar; // Notice 顯示
callUndefFunc(); // Fatal Error 顯示
?>
關鍵點:error_reporting(0)只隱藏輸出,不阻止致命錯誤導致腳本中斷。生產環境應配合display_errors = Off、log_errors = On將錯誤寫入日誌文件。
使用 set_error_handler() 註冊回調函數,可實現:
true 表示已處理,腳本繼續)<?php
function customErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
// 忽略 error_reporting 設定外的錯誤
if (!(error_reporting() & $errno)) return false;
$log = "[".date('c')."] [$errno] $errstr in $errfile:$errline\n";
error_log($log, 3, __DIR__.'/logs/php_errors.log'); // 寫入文件
// 生產環境:返回友好頁面或 JSON
if (php_sapi_name() !== 'cli') {
http_response_code(500);
echo '{"error":"系統繁忙,請稍後再試","code":500}';
exit;
}
return true; // 不讓 PHP 內置處理器繼續
}
set_error_handler('customErrorHandler');
// 觸發測試
trigger_error('測試用戶級錯誤', E_USER_WARNING);
?>
PHP 7+ 將多數致命錯誤轉為 Throwable 異常,可配合 set_exception_handler()、register_shutdown_function() 實現全棧捕獲:
set_exception_handler(function($e) {
// 記錄異常...
echo '系統錯誤,已記錄';
});
register_shutdown_function(function() {
$err = error_get_last();
if ($err && in_array($err['type'], [E_ERROR, E_PARSE, E_CORE_ERROR])) {
// 捕獲致命錯誤
}
});
error_reporting(E_ALL); ini_set('display_errors', 1);error_reporting(E_ALL); ini_set('display_errors', 0); ini_set('log_errors', 1); ini_set('error_log', '/var/log/php/error.log');try-catch 包裹業務邏輯,避免未捕獲異常導致 500。