在本教程中,您將學(xué)習(xí)如何使用PHP的錯誤處理功能來優(yōu)雅地處理錯誤情況。
有時,您的應(yīng)用程序?qū)o法正常運行,從而導(dǎo)致錯誤。有多種可能導(dǎo)致錯誤的原因,例如:
Web服務(wù)器可能磁盤空間不足
用戶可能在表單字段中輸入了無效的值
您嘗試訪問的文件或數(shù)據(jù)庫記錄可能不存在
應(yīng)用程序可能沒有寫磁盤上文件的權(quán)限
應(yīng)用程序需要訪問的服務(wù)可能暫時不可用
這些類型的錯誤稱為運行時錯誤,因為它們在腳本運行時發(fā)生。它們不同于在腳本運行之前需要修復(fù)的語法錯誤。
專業(yè)的應(yīng)用程序必須具有適當(dāng)處理此類運行時錯誤的功能。通常,這意味著更清楚,準(zhǔn)確地將問題告知用戶究竟發(fā)生了什么。
通常,當(dāng)出現(xiàn)導(dǎo)致腳本無法正常運行的問題時,PHP引擎會觸發(fā)錯誤。每個錯誤都由一個整數(shù)值和一個關(guān)聯(lián)的常數(shù)表示。下表列出了一些常見的錯誤級別:
錯誤等級 | 值 | 描述 |
---|---|---|
E_ERROR | 1 | 致命的運行時錯誤,無法恢復(fù)。 腳本的執(zhí)行將立即停止。 |
E_WARNING | 2 | 運行時警告。它不是致命的,大多數(shù)錯誤都屬于這一類。腳本的執(zhí)行不會停止。 |
E_NOTICE | 8 | 運行時通知。指示腳本遇到了可能發(fā)生錯誤的情況,盡管在正常運行腳本時也可能發(fā)生這種情況。 |
E_USER_ERROR | 256 | 用戶生成的致命錯誤消息。這類似于E_ERROR,只是它是由PHP腳本使用函數(shù)trigger_error()而不是PHP引擎生成的。 |
E_USER_WARNING | 512 | 非致命的用戶生成的警告消息。 這類似于E_WARNING,但它是由PHP腳本使用函數(shù)trigger_error()而不是PHP引擎生成的。 |
E_USER_NOTICE | 1024 | 用戶生成的通知消息。 這類似于E_NOTICE,但它是由PHP腳本使用函數(shù)trigger_error()而非PHP引擎生成的。 |
E_STRICT | 2048 | 嚴(yán)格來說不是錯誤,但只要PHP遇到可能導(dǎo)致問題或向前不兼容的代碼就會觸發(fā) |
E_ALL | 8191 | 所有錯誤和警告,PHP 5.4.0之前的E_STRICT除外。 |
有關(guān)更多錯誤級別,請查閱有關(guān)PHP錯誤級別的參考。
每當(dāng)PHP腳本遇到問題時,PHP引擎都會觸發(fā)錯誤,但是您也可以自己觸發(fā)錯誤,以生成更多用戶友好的錯誤消息。這樣,您可以使應(yīng)用程序更加復(fù)雜。以下部分描述了一些用于處理PHP錯誤的常用方法:
考慮以下示例,該示例僅嘗試以只讀方式打開文本文件。
<?php //嘗試打開不存在的文件 $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.phpon 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."); } ?>
現(xiàn)在,如果您運行上述腳本,您將得到如下錯誤消息:
Error: The file you are trying to access doesn't exist.
正如您可以看到的,通過在嘗試訪問文件之前實現(xiàn)簡單的檢查文件是否存在,我們可以生成對用戶更有意義的錯誤消息。
如果未找到“ sample.txt”文件,則上面使用的die()函數(shù)僅顯示自定義錯誤消息并終止當(dāng)前腳本。
您可以創(chuàng)建自己的錯誤處理函數(shù)來處理PHP引擎生成的運行時錯誤。 自定義錯誤處理程序為您提供了更大的靈活性和對錯誤的更好控制,它可以檢查錯誤并決定如何處理錯誤,它可能會向用戶顯示一條消息、將錯誤記錄在文件或數(shù)據(jù)庫中或通過電子郵件發(fā)送、嘗試修復(fù)問題并繼續(xù)、退出腳本執(zhí)行或完全忽略錯誤。
自定義錯誤處理函數(shù)必須能夠處理至少兩個參數(shù)(errno和errstr),但是它可以選擇接受另外三個參數(shù)(errfile、errline和errcontext),如下所述:
參數(shù) | 描述 |
---|---|
必需 - 以下參數(shù)是必需的 | |
errno | 以整數(shù)形式指定錯誤級別。這對應(yīng)于適當(dāng)?shù)腻e誤級別常量(E_ERROR,E_WARNING等) |
errstr | 將錯誤消息指定為字符串 |
可選 - 以下參數(shù)是可選的 | |
errfile | 以字符串形式指定發(fā)生錯誤的腳本文件的文件名 |
errline | 以字符串形式指定發(fā)生錯誤的行號 |
errcontext | 指定一個數(shù)組,其中包含發(fā)生錯誤時存在的所有變量及其值。對調(diào)試有用 |
下面是一個簡單的自定義錯誤處理函數(shù)示例。 無論多么微不足道,只要發(fā)生錯誤,就會觸發(fā)這個處理程序customError()。 然后,它將錯誤的詳細信息輸出到瀏覽器并停止執(zhí)行腳本。
<?php //錯誤處理函數(shù) function customError($errno, $errstr){ echo "<b>Error:</b> [$errno] $errstr"; } ?>
您需要告訴PHP使用您的自定義錯誤處理函數(shù)-只需調(diào)用內(nèi)置set_error_handler()函數(shù),并傳入函數(shù)名稱即可。
<?php //錯誤處理函數(shù) function customError($errno, $errstr){ echo "<b>Error:</b> [$errno] $errstr"; } //設(shè)置錯誤處理程序 set_error_handler("customError"); //觸發(fā)錯誤 echo($test); ?>
您還可以將錯誤的詳細信息記錄到日志文件中,如下所示:
<?php function calcDivision($dividend, $divisor){ if($divisor == 0){ trigger_error("calcDivision(): 除數(shù)不能為零", 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("出現(xiàn)問題,請重試。"); } set_error_handler("customError"); echo calcDivision(10, 0); echo "這個永遠不會被打印。"; ?>
您也可以使用相同的error_log()函數(shù)發(fā)送帶有錯誤詳細信息的電子郵件。
<?php function calcDivision($dividend, $divisor){ if ($divisor == 0){ trigger_error("calcDivision(): 除數(shù)不能為零", 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("出現(xiàn)問題,請重試。 錯誤報告已提交給網(wǎng)站管理員。"); } set_error_handler("customError"); echo calcDivision(10, 0); echo "這永遠不會被打印出來。"; ?>
盡管PHP引擎在遇到腳本問題時會觸發(fā)錯誤,但是您也可以自己觸發(fā)錯誤。這可以幫助使您的應(yīng)用程序更強大,因為它可以在潛在問題變成嚴(yán)重錯誤之前對其進行標(biāo)記。
要從腳本內(nèi)觸發(fā)錯誤,請調(diào)用trigger_error()函數(shù),并傳入要生成的錯誤消息:
trigger_error("出現(xiàn)問題了。");
考慮以下計算兩個數(shù)字除法的函數(shù)。
<?php function calcDivision($dividend, $divisor){ return($dividend / $divisor); } //調(diào)用函數(shù) echo calcDivision(10, 0); ?>
如果將零值作為$divisor參數(shù)傳遞,則PHP引擎生成的錯誤將類似于以下內(nèi)容:
Warning: Division by zero in C:\wamp\www\project\test.php on line 3
此消息看起來內(nèi)容不多??匆韵率褂胻rigger_error()函數(shù)生成錯誤的示例。
<?php function calcDivision($dividend, $divisor){ if($divisor == 0){ trigger_error("The divisor cannot be zero", E_USER_WARNING); return false; } else{ return($dividend / $divisor); } } //調(diào)用函數(shù) echo calcDivision(10, 0); ?>
現(xiàn)在,腳本生成此錯誤消息:
Warning: The divisor cannot be zero in C:\wamp\www\project\error.php on line 4
正如您看到的,第二個示例生成的錯誤消息與上一個示例相比更加清楚地說明了問題。