PHP 預設的錯誤輸出會直接暴露文件路徑、代碼行號等敏感資訊,這在生產環境中構成安全風險。同時,預設機制缺乏靈活的日誌記錄、用戶友好提示與錯誤分級處理能力。通過 set_error_handler()、set_exception_handler() 與 register_shutdown_function() 三大核心函數,我們可以構建一套完整的異常處理體系。
透過常量 DEBUG 區分環境:
if (defined('DEBUG')) {
error_reporting(E_ALL);
ini_set("display_errors", 1);
}
PHP 的致命錯誤無法通過 set_error_handler 捕獲,需使用 register_shutdown_function 在腳本結束時檢查:
function shutdownHandler() {
$lasterror = error_get_last();
if ($lasterror) {
// 記錄日誌
$error = date("Y-m-d h:i:s") . '=>' . "[SHUTDOWN] lvl:" . $lasterror['type']
. " | msg:" . $lasterror['message']
. " | file:" . $lasterror['file']
. " | ln:" . $lasterror['line'] . "\n";
file_put_contents('./log/' . date("Ymd") . 'shutdownlog.txt', $error, FILE_APPEND);
// 用戶友好提示
ob_end_clean();
die('對不起,系統出錯了!');
}
}
register_shutdown_function('shutdownHandler');
將所有 PHP 錯誤(除 Notice 與 Deprecated 外)轉為 ErrorException 統一處理:
function errorHandler($errno, $errstr = '', $errfile = '', $errline = 0) {
$exception = new \ErrorException($errstr, 0, $errno, $errfile, $errline);
$msg = date("Y-m-d h:i:s") . '=>' . 'Type:' . getErrTypeName($errno) . ' ' . getMsg($exception);
file_put_contents('./log/' . date("Ymd") . 'error.txt', $msg, FILE_APPEND);
// 忽略 Notice 與 Deprecated
switch ($errno) {
case E_NOTICE:
case E_DEPRECATED:
return;
}
throw $exception;
}
set_error_handler('errorHandler', E_ALL);
捕獲所有未被 try-catch 捕獲的異常,記錄完整堆疊資訊:
function exceptionHandler($ex) {
$msg = date("Y-m-d h:i:s") . '=>' . getMsg($ex);
file_put_contents('./log/' . date("Ymd") . 'exception.txt', $msg, FILE_APPEND);
}
set_exception_handler('exceptionHandler');
function getErrTypeName($errno) {
switch ($errno) {
case E_NOTICE: return 'E_NOTICE';
case E_DEPRECATED: return 'E_DEPRECATED';
default: return $errno;
}
}
function getMsg($exception) {
// 獲取最原始的異常(處理 Previous 鏈)
while ($exception->getPrevious()) {
$exception = $exception->getPrevious();
}
$msg = ' Message: ' . $exception->getMessage();
$msg .= ' File: ' . $exception->getFile() . ':' . $exception->getLine() . "\n";
return $msg;
}
程式碼按日期自動分割日誌文件:
shutdownlog.txt - 致命錯誤日誌error.txt - 標準錯誤日誌exception.txt - 異常日誌建議在生產環境配置 logrotate 定期清理舊日誌,避免磁碟佔用過大。
./log/ 目錄可寫入die() 替換為載入專用錯誤模板頁面適用版本:PHP 5.3+
核心函數:set_error_handler、set_exception_handler、register_shutdown_function、error_get_last