PHP 錯誤處理

在本教程中,你將學習如何使用 PHP 的錯誤處理函式來優雅地處理錯誤情況。

處理錯誤

有時你的應用程式將無法按預期執行,從而導致錯誤。有許多原因可能導致錯誤,例如:

  • Web 伺服器可能會用盡磁碟空間
  • 使用者可能在表單欄位中輸入了無效值
  • 你嘗試訪問的檔案或資料庫記錄可能不存在
  • 應用程式可能沒有寫入磁碟上檔案的許可權
  • 應用程式需要訪問的服務可能暫時不可用

這些型別的錯誤稱為執行時錯誤,因為它們在指令碼執行時發生。它們與在指令碼執行之前需要修復的語法錯誤不同。

專業應用程式必須具有正常處理此類執行時錯誤的功能。通常這意味著更清楚,更準確地告知使用者問題。

瞭解錯誤級別

通常,當存在阻止指令碼正常執行的問題時,PHP 引擎會觸發錯誤。每個錯誤由整數值和相關常量表示。下表列出了一些常見錯誤級別:

錯誤級別 描述
E_ERROR 1 致命的執行時錯誤,無法從中恢復。立即停止執行指令碼。
E_WARNING 2 執行時警告。它是非致命的,大多數錯誤往往屬於這一類。不停止執行指令碼。
E_NOTICE 8 執行時通知。指示指令碼遇到可能出錯的內容,儘管在正常執行指令碼時也可能出現這種情況。
E_USER_ERROR 256 致命的使用者生成的錯誤訊息。這類似於 E_ERROR ,除了它是由 PHP 指令碼使用函式 trigger_error() 而不是 PHP 引擎生成的。
E_USER_WARNING 512 非致命的使用者生成的警告訊息。這就像是一個 E_WARNING ,除了它是由 PHP 指令碼使用函式 trigger_error() 而不是 PHP 生成的。發動機
E_USER_NOTICE 1024 使用者生成的通知訊息。這類似於 E_NOTICE ,除了它是由 PHP 指令碼使用函式 trigger_error() 而不是 PHP 引擎生成的。
E_STRICT 2048 並非嚴格意義上的錯誤,但只要 PHP 遇到可能導致問題或轉發不相容的程式碼就會觸發
E_ALL 8191 E_STRICT PHP 5.4.0 之外的所有錯誤和警告。

有關更多錯誤級別,請檢視有關 PHP 錯誤級別 的參考。

PHP 引擎在遇到指令碼問題時會觸發錯誤,但你也可以自己觸發錯誤以生成更多使用者友好的錯誤訊息。這樣,你可以使你的應用程式更加順暢。以下部分描述了用於處理 PHP 中的錯誤的一些常用方法:

使用 die() 函式來做基本錯誤處理

請考慮以下示例,它只是嘗試開啟文字檔案以進行只讀。

<?php
// Try to open a non-existent file
$file = fopen("sample.txt", "r");
?>

如果該檔案不存在,你可能會收到如下錯誤:

Warning: fopen(sample.txt) [function.fopen]: failed to open stream: No such file or directory in C:\wamp\www\project\test.php on line 2 

如果我們遵循一些簡單的步驟,我們可以阻止使用者收到此類錯誤訊息。

<?php
if(file_exists("sample.txt")){
    $file = fopen("sample.txt", "r");
} else{
    die("Error: The file you are trying to access doesn't exist.");
}
?>

現在,如果你執行上面的指令碼,你將收到如下錯誤訊息:

Error: The file you are trying to access doesn't exist. 

正如你在嘗試訪問檔案之前通過簡單檢查檔案是否存在所看到的那樣,我們可以生成對使用者更有意義的錯誤訊息。

上面使用的 die() 函式只顯示自定義錯誤訊息,如果找不到’sample.txt’檔案,則終止當前指令碼。

建立自定義錯誤處理程式

你可以建立自己的錯誤處理函式來處理 PHP 引擎生成的執行時錯誤。自定義錯誤處理程式為你提供更大的靈活性和更好的錯誤控制,它可以檢查錯誤並決定如何處理錯誤,它可能向使用者顯示訊息,在檔案或資料庫中記錄錯誤或傳送郵件,嘗試解決問題並繼續,退出指令碼的執行或完全忽略錯誤。

自定義錯誤處理程式函式必須能夠處理至少兩個引數(errno 和 errstr),但是它可以選擇接受另外三個引數(errfile,errline 和 errcontext),如下所述:

引數 描述
必需
errno 以整數形式指定錯誤級別。這對應於適當的錯誤級別常量(E_ERRORE_WARNING 等等)
errstr 將錯誤訊息指定為字串
可選
errfile 以字串形式指定發生錯誤的指令碼檔案的檔名
errline 以字串形式指定發生錯誤的行號
errcontext 指定一個陣列,其中包含發生錯誤時存在的所有變數及其值。用於除錯

這是一個簡單的自定義錯誤處理函式的示例。 customError() 無論多麼微不足道,只要發生錯誤,就會觸發此處理程式。然後它將錯誤的詳細資訊輸出到瀏覽器並停止執行指令碼。

<?php
// Error handler function
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}
?>

你需要告訴 PHP 使用你的自定義錯誤處理函式 - 只需呼叫內建 set_error_handler() 函式,傳入函式的名稱。

<?php
// Error handler function
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}
 
// Set error handler
set_error_handler("customError");
 
// Trigger error
echo($test);
?>

錯誤記錄

記錄文字檔案中的錯誤訊息

你還可以將錯誤的詳細資訊記錄到日誌檔案中,如下所示:

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("calcDivision(): The divisor cannot be zero", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}
function customError($errno, $errstr, $errfile, $errline, $errcontext){
    $message = date("Y-m-d H:i:s - ");
    $message .= "Error: [" . $errno ."], " . "$errstr in $errfile on line $errline, ";
    $message .= "Variables:" . print_r($errcontext, true) . "\r\n";
    
    error_log($message, 3, "logs/app_errors.log");
    die("There was a problem, please try again.");
}
set_error_handler("customError");
echo calcDivision(10, 0);
echo "This will never be printed.";
?>

通過電子郵件傳送錯誤訊息

你還可以使用相同的 error_log() 功能傳送包含錯誤詳細資訊的電子郵件。

<?php
function calcDivision($dividend, $divisor){
    if ($divisor == 0){
        trigger_error("calcDivision(): The divisor cannot be zero", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}
function customError($errno, $errstr, $errfile, $errline, $errcontext){
    $message = date("Y-m-d H:i:s - ");
    $message .= "Error: [" . $errno ."], " . "$errstr in $errfile on line $errline, ";
    $message .= "Variables:" . print_r($errcontext, true) . "\r\n";
    
    error_log($message, 1, "webmaster@example.com");
    die("There was a problem, please try again. Error report submitted to webmaster.");
}
set_error_handler("customError");
echo calcDivision(10, 0);
echo "This will never be printed.";
?>

觸發錯誤

儘管 PHP 引擎在遇到指令碼問題時會觸發錯誤,但你也可以自己觸發錯誤。這有助於使你的應用程式更加健壯,因為它可以在潛在問題變成嚴重錯誤之前對其進行標記。

要從指令碼中觸發錯誤,請呼叫該 trigger_error() 函式,並傳入要生成的錯誤訊息:

trigger_error ("There was a problem."); 

考慮以下函式來計算兩個數字的除法。

<?php
function calcDivision($dividend, $divisor){
    return($dividend / $divisor);
}
 
// Calling the function
echo calcDivision(10, 0);
?>

如果將值 0 作為 $divisor 引數傳遞,則 PHP 引擎生成的錯誤將如下所示:

Warning: Division by zero in C:\wamp\www\project\test.php on line 3 

此訊息看起來不太有用。請考慮以下使用該 trigger_error() 函式生成錯誤的示例。

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("The divisor cannot be zero", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}
 
// Calling the function
echo calcDivision(10, 0);
?>

現在該指令碼生成此錯誤訊息:

Warning: The divisor cannot be zero in C:\wamp\www\project\error.php on line 4 

如你所見,第二個示例生成的錯誤訊息與前一個示例相比更清楚地解釋了問題。