PHP 核心特性 - 錯誤處理

錯誤與異常

錯誤,能夠理解程序自己的錯誤,例如語法錯誤。而異常則更偏向於程序運行不符合預期或者不符合正常流程;對於 PHP 語言而言,處理錯誤和處理異常使用的機制徹底不一樣,所以很容易讓人產生困惑。php

例如,咱們但願經過捕獲異常來處理除數爲 0 的狀況,可是在捕獲到異常以前,PHP 就觸發了錯誤。laravel

1 try {
2     $a = 5 / 0;
3 } catch (Exception $e) {
4     $e->getMessage();
5     $a = -1;  // 經過異常來處理 $a 爲 0 的狀況,可是實際上,捕獲不到該異常
6 }
7 
8 echo $a;
9 // PHP Warning:  Division by zero

 

也就是說,PHP 將除數爲 0 的狀況當成了錯誤而觸發,而不會自動拋出異常,所以無法捕獲。相似的,在不少狀況下,PHP 都沒辦法自動拋出異常。只能經過 if - else 語句判斷再結合 throw 方法來並手動拋出異常。sql

上述狀況的發生,主要仍是由於異常機制是 PHP 向面向對象演進後獲得的產物。而在此以前 PHP 的報錯主要仍是經過錯誤機制,所以,在不少狀況下,PHP 的錯誤要比異常更有價值。不過 PHP7 開始統一這二者,使錯誤也能夠像異常那樣拋出(這部份內容將放在異常部分講解)。shell

 

錯誤級別

PHP 中的錯誤可理解爲 使腳本不運行不正常的狀況,根據錯誤級別從高到低可劃分爲五類服務器

  1. Parse error 或 Syntax Error - 語法解析錯誤,觸發該錯誤後,腳本徹底沒法運行;
  2. Fatal Error - 致命錯誤,觸發該錯誤後,後面的腳本沒法繼續執行;
  3. Warning Error - 出現比較不恰當的地方,腳本可繼續執行;
  4. Notice Error - 出現不恰當的地方,可是程度比 Warning Error 低,腳本可繼續執行;
  5. Deprecated Error - 不推薦這麼使用,將來可能會廢棄,腳本可繼續執行;

默認狀況下,PHP 觸發錯誤,並顯示錯誤的級別及對應的提示。架構

Parse Error 示例 - 語句結尾不寫分號併發

1 echo "abc"
2 // PHP Parse error:  syntax error, unexpected end of file, expecting ',' or ';

 

Fatal Error 示例 - 使用不存在的函數分佈式

1 echo "before\n";
2 foo();
3 echo "after"; // 本行沒法繼續執行
4 // before
5 // PHP Fatal error:  Uncaught Error: Call to undefined function foo()

 

Warning Error 示例 - 引入不存在的文件函數

 1 $a = "foo";
 2 include('bar.php');
 3 echo $a; // 程序繼續執行
 4 // PHP Warning:  include(bar.php): failed to open stream: No such file or directory ...
 5 // foo
 6 Notice Error 示例 - 輸出不存在的變量
 7 
 8 echo $foo;
 9 echo 12345;
10 // PHP Notice:  Undefined variable: foo
11 // 12345

 

Deprecated Error 示例 - 在一些字符串函數中傳入數字而非字符串微服務

1 strpos('12345', 3);
2 // PHP Deprecated:  strpos(): Non-string needles will be interpreted as strings in the future

 

除了默認觸發消息外,用戶也能夠使用 set_error_handler 函數自定義錯誤處理,大多數錯誤類型均可以進行自定義處理,除了 E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING 外。

1 set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] ) : mixed

 

示例

 1 <?php
 2 // E_ALL - 處理所有錯誤類型
 3 set_error_handler('customError', E_ALL);
 4 
 5 /**
 6  * @param  int $errno 錯誤的級別
 7  * @param  string $errstr  錯誤的信息
 8  * @param  string $errfile 錯誤的文件名(可選)
 9  * @param  string $errline 錯誤發生的行號(可選)
10  */
11 function customError(int $errno, string $errstr, string $errfile, string $errline)
12 {
13     echo sprintf('錯誤消息爲 %s', $errstr);
14 }
15 
16 $a = 5 / 0;  // 錯誤消息爲 Division by zero

 

用戶也能夠經過 trigger_error 函數來手動觸發一個用戶級別的錯誤(E_USER_ERRORE_USER_WARNINGE_USER_NOTICEE_USER_DEPRECATED)。

1 function division($a, $b) {
2     if($b == 0){
3         @trigger_error("0 不能做爲除數", E_USER_NOTICE);
4         return -1;
5     }
6     return $a / $b;
7 }
8 
9 echo division(10, 0);

 

 

與錯誤有關的配置

一些錯誤處理相關的經常使用配置

  • error_reporting - 設置錯誤的報告級別
  • display_errors - 是否顯示錯誤
  • display_startup_error - 是否顯示 PHP 啓動過程當中的顯示
  • log_errors - 設置是否將腳本運行的錯誤信息記錄到服務器錯誤日誌或者 error_log 之中

《Modern PHP》提出了四個規則

  1. 必定要讓 PHP 報告錯誤;
  2. 在開發環境中要顯示錯誤;
  3. 在生產環境中不能顯示錯誤;
  4. 在開發環境和生產環境中都要記錄錯誤;

開發環境推薦配置

1 display_errors = On
2 display_startup_error = On
3 error_reporting = -1
4 log_errors = On

 

生產環境推薦配置

1 display_errors = Off
2 display_startup_error = Off
3 ; 報告 Notice 之外的全部錯誤
4 error_reporting = E_ALL & ~E_NOTICE
5 log_errors = On
6  

 

Symfony 編碼規範相關

異常和錯誤消息字符串必須使用 sprintf 來進行拼接;

throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));

當錯誤類型爲 E_USER_DEPRECATED 時,須要添加 @

@trigger_error("foo", E_USER_DEPRECATED);

參考資料

相關文章
相關標籤/搜索