不記起來會忘記,雖然記起來會混亂,寫個筆記紀錄一下
本文將介紹如何觸發錯誤、錯誤級別介紹、處理錯誤、錯誤日誌的寫法。
觸發錯誤
使用 Exception 類別
這種方式用於例外處理,當你想捕捉並處理某些條件下的錯誤時,可以拋出一個例外。這通常用於邏輯錯誤或應用程式級別的錯誤。
try {
    throw new Exception("Division by zero.");
} catch (Exception $e) {
    echo "Caught exception: " . $e->getMessage();
}使用 Error 類別
Error 類別是從 PHP 7 開始引入的,用於處理更底層的錯誤,例如語法錯誤或類型錯誤。這些錯誤通常表示程式碼中的嚴重問題,應該被捕捉並記錄。
try {
    throw new Error("Division by zero.");
} catch (Error $e) {
    echo "Caught error: " . $e->getMessage();
}
使用 trigger_error 函數
trigger_error 函數允許你生成一個用戶定義的錯誤。這對於在開發過程中發出警告或錯誤訊息非常有用。你可以指定錯誤等級,例如 E_USER_WARNING 或 E_USER_ERROR。
trigger_error("This is a user-generated warning.", E_USER_WARNING);
trigger_error("This is a user-generated error.", E_USER_ERROR);範例對比
以下是一個綜合範例,展示了這三種錯誤發出的方式及其處理方法:
// 自訂錯誤處理函數
function customErrorHandler($errno, $errstr, $errfile, $errline) {
    error_log("Error: [$errno] $errstr - $errfile:$errline");
    echo "Handled error: $errstr<br>";
    return true;
}
// 設定自訂錯誤處理函數
set_error_handler("customErrorHandler");
// 使用 Exception
try {
    throw new Exception("This is an exception.");
} catch (Exception $e) {
    echo "Caught exception: " . $e->getMessage() . "<br>";
}
// 使用 Error
try {
    throw new Error("This is an error.");
} catch (Error $e) {
    echo "Caught error: " . $e->getMessage() . "<br>";
}
// 使用 trigger_error
trigger_error("This is a user-generated warning.", E_USER_WARNING);
trigger_error("This is a user-generated error.", E_USER_ERROR);
// 此行仍然會被執行
echo "hello world!";
這個範例中,Exception 和 Error 被捕捉並處理,而 trigger_error 生成的錯誤則由自訂錯誤處理函數處理。程式不會中止,並且會輸出所有錯誤訊息。
錯誤級別表
系統級別錯誤
| 錯誤級別 | 中止程式 | 引發者 | 情境描述 | 
|---|---|---|---|
| E_ERROR | 是 | 系統 | 致命的運行錯誤,例如無效的函數調用 | 
| E_WARNING | 否 | 系統 | 運行時警告,例如包含不存在的文件 | 
| E_PARSE | 是 | 系統 | 解析錯誤,例如語法錯誤 | 
| E_NOTICE | 否 | 系統 | 運行時通知,例如使用未定義的變數 | 
| E_CORE_ERROR | 是 | 系統 | PHP 啟動時的致命錯誤 | 
| E_CORE_WARNING | 否 | 系統 | PHP 啟動時的警告 | 
| E_COMPILE_ERROR | 是 | 系統 | 編譯時的致命錯誤 | 
| E_COMPILE_WARNING | 否 | 系統 | 編譯時的警告 | 
| E_STRICT | 否 | 系統 | 建議的代碼改進措施 | 
| E_RECOVERABLE_ERROR | 否 | 系統 | 可捕捉的致命錯誤,例如類型錯誤 | 
| E_DEPRECATED | 否 | 系統 | 運行時通知,不建議使用的代碼 | 
用戶級別錯誤
| 錯誤級別 | 中止程式 | 引發者 | 情境描述 | 
|---|---|---|---|
| E_USER_ERROR | 是 | 用戶 trigger_error() | 用戶生成的致命錯誤,例如自訂的致命錯誤 | 
| E_USER_WARNING | 否 | 用戶 trigger_error() | 用戶生成的警告,例如自訂的警告訊息 | 
| E_USER_NOTICE | 否 | 用戶 trigger_error() | 用戶生成的通知,例如自訂的通知訊息 | 
| E_USER_DEPRECATED | 否 | 用戶 trigger_error() | 用戶生成的過時警告,例如自訂的不建議使用的代碼警告 | 
處理錯誤
以下介紹錯誤處裡的方法:
set_error_handler
set_exception_handler
register_shutdown_function
使用 set_error_handler 處理的錯誤
| 錯誤級別 | 會中止程式 | 引發者 | 簡單描述情境 | 
|---|---|---|---|
| E_WARNING | 否 | 系統 | 運行時警告,例如包含不存在的文件 | 
| E_NOTICE | 否 | 系統 | 運行時通知,例如使用未定義的變數 | 
| E_USER_WARNING | 否 | 用戶 ( trigger_error()) | 用戶生成的警告 | 
| E_USER_NOTICE | 否 | 用戶 ( trigger_error()) | 用戶生成的通知 | 
| E_USER_ERROR | 是 | 用戶 ( trigger_error()) | 用戶生成的致命錯誤 | 
| E_USER_DEPRECATED | 否 | 用戶 ( trigger_error()) | 用戶生成的過時警告 | 
| E_DEPRECATED | 否 | 系統 | 運行時通知,不建議使用的代碼 | 
| E_RECOVERABLE_ERROR | 否 | 系統 | 可捕捉的致命錯誤,例如類型錯誤 | 
使用 set_exception_handler 處理的例外
| 錯誤類型 | 會中止程式 | 引發者 | 簡單描述情境 | 
|---|---|---|---|
| Exception | 是 | 用戶 | 例如 throw new Exception | 
| Error | 是 | 用戶 | 例如 throw new Error | 
使用 register_shutdown_function 處理的錯誤
| 錯誤級別 | 會中止程式 | 引發者 | 簡單描述情境 | 
|---|---|---|---|
| E_ERROR | 是 | 系統 | 致命的運行錯誤,例如無效的函數調用 | 
| E_CORE_ERROR | 是 | 系統 | PHP 啟動時的致命錯誤 | 
| E_COMPILE_ERROR | 是 | 系統 | 編譯時的致命錯誤 | 
| E_PARSE | 是 | 系統 | 解析錯誤,例如語法錯誤 | 
這些表格展示了不同的錯誤處理方法以及它們可以處理的錯誤類型,確保你可以有效地處理所有可能發生的錯誤和例外。
錯誤處裡範例
set_error_handler()
系統只會有一個有作用的 set_error_handler(),後面設置的 handler 會覆蓋前面設置 handler,無法刪除,如有套件設置了,可以用覆蓋的或 set_error_handler(null) 使 handler 失去作用
try-catch
捕獲到 Error or Exception 可統一進行錯誤處裡,當然也可以捕獲後步處理,或存於 error_log
// 自訂錯誤處理函數
function customErrorHandler($errno, $errstr, $errfile, $errline) {
    echo "Handled error: [$errno] $errstr - $errfile:$errline<br>";
    // 記錄錯誤到日誌文件
    error_log("Error: [$errno] $errstr - $errfile:$errline");
    return true; // 返回 true 以避免 PHP 預設的錯誤處理
}
// 設定自訂錯誤處理函數
set_error_handler("customErrorHandler");
// 捕獲和處理 Exception 和 Error 的自訂處理函數
function handleExceptionOrError($e) {
    $errno = ($e instanceof Error) ? E_USER_ERROR : E_USER_WARNING;
    customErrorHandler($errno, $e->getMessage(), $e->getFile(), $e->getLine());
}
// 捕獲和處理 Exception
try {
    throw new Exception(" Exception: massage.");
} catch (Exception $e) {
    // 呼叫 handleExceptionOrError 處理 Exception
    handleExceptionOrError($e);
}
// 捕獲和處理 Error
try {
    throw new Error(" Error: massage.");
} catch (Error $e) {
    // 呼叫 customErrorHandler 處理 Error
    customErrorHandler($errno, $e->getMessage(), $e->getFile(), $e->getLine());
}輸出:
Handled error: [512] Exception: massage. - C:\...\system\modules\error\try-catch.php:21
Handled error: [8] Undefined variable: errno - C:\...\system\modules\error\try-catch.php:32
Handled error: [] Error: massage. - C:\...\system\modules\error\try-catch.php:29錯誤日誌
錯誤日誌就像飛機的黑盒子,記錄著所有錯誤發生的詳細信息,讓我們能夠在錯誤發生後進行分析和診斷,從而提高應用程式的穩定性和可靠性。
以下是錯誤日誌寫法:
// 1. 將錯誤訊息寫入到 PHP 的系統日誌
error_log("Error occurred.");
// 2. 將錯誤訊息發送到指定的 email 地址
error_log("Error occurred.", 1, "[email protected]");
// 3. 將錯誤訊息發送到 PHP 的測試工具連接
error_log("Error occurred.", 2);
// 4. 將錯誤訊息附加到指定的文件
error_log("Error occurred.", 3, "/path/to/your/error.log");綜合錯誤處裡
// 自訂錯誤處理函數
function customErrorHandler($errno, $errstr, $errfile, $errline) {
    $errorMessage = "Error: [$errno] $errstr - $errfile:$errline\n";
    
    // 根據錯誤級別記錄到不同的日誌文件
    switch ($errno) {
        case E_USER_ERROR:
            error_log($errorMessage, 3, "/path/to/your/user_error.log");
            break;
        case E_USER_WARNING:
            error_log($errorMessage, 3, "/path/to/your/user_warning.log");
            break;
        case E_USER_NOTICE:
            error_log($errorMessage, 3, "/path/to/your/user_notice.log");
            break;
        default:
            error_log($errorMessage, 3, "/path/to/your/general_error.log");
            break;
    }
    
    echo "Handled error: $errstr<br>";
    return true;
}
// 自訂例外處理函數
function customExceptionHandler($exception) {
    $errorMessage = "Exception: " . $exception->getMessage() . "\n";
    
    // 根據例外類型記錄到不同的日誌文件
    if ($exception instanceof Error) {
        error_log($errorMessage, 3, "/path/to/your/error.log");
    } else {
        error_log($errorMessage, 3, "/path/to/your/exception.log");
    }
    
    echo "Handled exception: " . $exception->getMessage() . "<br>";
}
// 自訂關閉時的錯誤處理函數
function shutdownHandler() {
    $error = error_get_last();
    if ($error !== NULL) {
        $errorMessage = "Shutdown error: " . $error['message'] . "\n";
        error_log($errorMessage, 3, "/path/to/your/shutdown_error.log");
        echo "Handled shutdown error: " . $error['message'] . "<br>";
    }
}
// 設定自訂錯誤和例外處理函數
set_error_handler("customErrorHandler");
set_exception_handler("customExceptionHandler");
register_shutdown_function("shutdownHandler");
// 觸發例外和錯誤
try {
    throw new Exception("This is an exception.");
} catch (Exception $e) {
    customExceptionHandler($e);
}
try {
    throw new Error("This is an error.");
} catch (Error $e) {
    customExceptionHandler($e);
}
trigger_error("This is a user-generated notice.", E_USER_NOTICE);
trigger_error("This is a user-generated warning.", E_USER_WARNING);
trigger_error("This is a user-generated error.", E_USER_ERROR);
// 此行可能不會執行,因為 E_USER_ERROR 是致命錯誤
echo "hello world!";錯誤日誌的記錄不僅有助於在開發過程中及早發現和修復問題,還能在生產環境中提供寶貴的錯誤追蹤信息。透過詳細的錯誤日誌記錄,我們可以了解錯誤發生的時間、錯誤類型、錯誤訊息以及錯誤發生的文件和行號,這些資訊讓我們快速修正非常重要。
