淺談PHP異常處理


1、PHP中異常的獨特性

  PHP中的異常的獨特性,即PHP中的異常不同於主流語言C++、java中的異常。在Java中,異常是唯一的錯誤報告方式,而在PHP中卻不是這樣,而是把所有不正常的情況都視作了錯誤進行處理。這兩種語言對異常和錯誤的界定存在分歧。什么是異常什么是錯誤,兩種語言的設計者存在不同的觀點。

  PHP中的異常:

  是程序在運行中出現不符合預期的情況及與正常流程不同的狀況。一種不正常的情況,按照正常邏輯本不該出的錯誤,但仍然會出現的錯誤,這是屬於邏輯和業務流程的錯誤,而不是編譯或者語法上的錯誤。

  PHP中的錯誤:

  是屬於php腳本自身的問題,大部分情況是由錯誤的語法,服務器環境導致,使得編譯器無法通過檢查,甚至無法運行的情況。warning、notice都是錯誤,只是他們的級別不同而已,並且錯誤是不能被try-catch捕獲的。

   在PHP中遇到任何自身錯誤都會觸發一個錯誤,而不是拋出異常。PHP一旦遇到非正常代碼,通常都會觸發錯誤,而不是拋出異常。因此,如果想要使用異常處理不可預料的問題,是辦不到的。

典型例子:

1 <?php
2 
3 try {
4     echo 1/0;
5 } catch (Exception $e){
6     echo $e->getMessage();
7 }

結果:

結果顯示:

  此時出現了一個警告級別的錯誤,程序終止。

結論:
  PHP通常是無法自動捕獲有意義的異常,它把所有不正常的情況都視作了錯誤,你要想捕獲異常就得使用if....else結構,保證代碼是正常的,然后判斷進行手動拋出異常。

2、PHP中的錯誤級別

   PHP中的異常機制是不足的,絕大多數情況下無法自動拋出異常,必須使用if....else語句先進行判斷,在進行手動拋出異常。

  手動拋出異常的意義不大,是已經預料到的錯誤,這種方式將會使你陷入紛繁復雜的業務邏輯判斷和處理中。

  因此我們可以通過一些特殊的函數來自定義錯誤處理函數,來接管PHP原生的錯誤處理函數,然后再進行拋出異常。

  接下來我們需要了解PHP中的一些錯誤。

錯誤顯示控制:

  【ALL設置】

  全局:php.ini中設置display_error = on/off;

  局部:ini_set("display_error", true/false);

PHP.ini中display_errors = Off失效的解決 
  問題: PHP設置文件php.ini中明明已經設置display_errors = Off,但是在運行過程中,網頁上還是會出現錯誤信息。 
  解決: 經 查log_errors= On,據官方的說法,當這個log_errors設置為On,那么必須指定error_log文件,如果沒指定或者指定的文件沒有權限寫入,那么照樣會輸 出到正常的輸出渠道,那么也就使得display_errors 這個指定的Off失效,錯誤信息還是打印了出來。於是將log_errors = Off,問題就解決了。

  【選擇性設置顯示錯誤】

  全局:error_reporting = E_ALL | E_STRICT....

  局部:error_reporting(E_ERROR | E_WARNING | E_PARSE)

1     E_ERROR           致命的運行錯誤。錯誤無法恢復,暫停執行腳本。
2     E_WARNING         運行時警告(非致命性錯誤)。非致命的運行錯誤,腳本執行不會停止。
4     E_PARSE           編譯時解析錯誤。解析錯誤只由分析器產生。
8     E_NOTICE          運行時提醒(這些經常是你代碼中的bug引起的,也可能是有意的行為造成的。)
16    E_CORE_ERROR PHP  啟動時初始化過程中的致命錯誤。
32    E_CORE_WARNING    PHP啟動時初始化過程中的警告(非致命性錯)。
64    E_COMPILE_ERROR   編譯時致命性錯。這就像由Zend腳本引擎生成了一個E_ERROR。
128   E_COMPILE_WARNING 編譯時警告(非致性錯)。這就像由Zend腳本引擎生成了E_WARNING警告。
256   E_USER_ERROR      自定義錯誤消息。像用PHP函數trigger_error(程序員設置E_ERROR)
512   E_USER_WARNING    自定義警告消息。像用PHP函數trigger_error(程序員設的E_WARNING警告) 
1024  E_USER_NOTICE     自定義的提醒消息。像由使用PHP函數trigger_error(程序員E_NOTICE集)
2048  E_STRICT          編碼標准化警告。允許PHP建議修改代碼以確保最佳的互操作性向前兼容性。 
4096  E_RECOVERABLE_ERROR   開捕致命錯誤。像E_ERROR,但可以通過用戶定義的處理捕獲(又見set_error_handler())
8191  E_ALL             所有的錯誤和警告(不包括 E_STRICT) (E_STRICT will be part of E_ALL as of PHP 6.0)14 16384 E_USER_DEPRECATED 15 30719 E_ALL

   一共有十五種,使用二進制代替,0000 0000 0000 0011 表示 E_ERROR和E_WARNING

  例如:

  error_reporting(3);  //只顯示E_ERROR和E_WARNING錯誤

  error_reporting(-1);  //只顯示所有錯誤誤

 注意:

  在開發階段通常是顯示所有錯誤,方便解決問題;

  在生產階段通常是隱藏錯誤,並將需錯誤記錄到文件中(錯誤日志);

  php.ini中設置:log_error = on/off;  //記錄、不記錄

         error_log = php_errors.log  //設定錯誤日志文件(此時沒有給定路徑則在當前位置生成)

  還可以通過ini_set()進行設置。

 

3、PHP中的異常處理

  3.1、set_error_handler(error_function, error_type)

  使用set_error_handler(error_function, error_type)函數設置自定義錯誤處理函數,接管原錯誤處理函數。

eg.

 1 <?php
 2 
 3 // 方式一
 4 // set_error_handler('myError');
 5 // function myError($errorNum, $errorMs, $errorFile, $errorLine){
 6 //     echo('set_error_handler: ' . $errorNum . ':' . $errorMs . ' in ' . $errorFile . ' on ' . $errorLine . ' line ');
 7 // }
 8 
 9 // 方式二
10 class ErrorClass{
11     // 必須靜態public方法
12     public static function myError($errorNum, $errorMs, $errorFile, $errorLine){
13     echo('set_error_handler: ' . $errorNum . ':' . $errorMs . ' in ' . $errorFile . ' on ' . $errorLine . ' line ');
14     }
15 }
16 
17 set_error_handler(['ErrorClass', 'myError']);
18 
19 
20 try {
21     $a = 5/0;
22 } catch (Exception $e) {
23     echo "666666";
24 }

訪問結果:

  由結果可知:我們自定義的myError方法截取了錯誤,此時我們可以主動的處理這些錯誤,拋出相應的異常。

  但是我們需要注意以下兩點:

  第一,如果存在該方法,相應的error_reporting()就不能在使用了。它將接管PHP原生錯誤處理函數,即所有的錯誤都會交給自定義的函數處理。
  第二,此方法不能處理以下級別的錯誤:E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,set_error_handler() 函數所在文件中產生的E_STRICT,該函數只能捕獲系統產生的一些Warning、Notice級別的錯誤。
注意:
  如果在腳本執行前發生錯誤,由於此時自定義的錯誤處理函數還沒有注冊,因此就用不到這個自定義錯誤處理程序。

  3.2、register_shutdown_function(exception_function) 

  捕獲PHP的錯誤:Fatal Error、Parse Error等, 這個方法是PHP腳本執行結束前最后一個調用的函數,比如腳本錯誤、die()、exit、異常、正常結束都會調用。
  通過這個函數就可以在腳本結束前判斷這次執行是否有錯誤產生,這時就要借助於一個函數:error_get_last();這個函數可以拿到本次執行產生的所有錯誤。error_get_last();返回的信息:
  [type]            - 錯誤類型
  [message]    - 錯誤消息
  [file]              - 發生錯誤所在的文件
  [line]             - 發生錯誤所在的行
注意:當parse-time出錯時是不會調用本函數的。只有在run-time出錯的時候,才會調用本函數。即需要成功注冊此函數才能使用。【測試3和測試4對比】

 eg.

 1 <?php
 2                 
 3 try {
 4     $a = 5/0;
 5 } catch (Exception $e) {
 6     echo "666666";
 7 }
 8     
 9 register_shutdown_function('myshutdownfunc');
10 function myshutdownfunc()
11 {
12     if ($error = error_get_last()) {
13         echo "<pre>";
14         print_r($error);
15         echo "</pre>";die;
16     }
17 }

 

測試1:

測試2:(使用echo "string";替換try....catch)

測試3:(使用echo "string"替換try...catch)

此時語法錯誤,register_shutdown_function函數未執行

 

測試4:

新建一個文件,具有語法錯誤的php代碼,並將其引入執行文件中,例如

 1 ceshi2.class.php文件
 2 <?php
 3 echo "string"
 4 
 5 ?>
 6 
 7 ceshi.class.php文件
 8 <?php
 9 
10 register_shutdown_function('myshutdownfunc');
11 function myshutdownfunc()
12 {
13     if ($error = error_get_last()) {
14         echo "<pre>";
15         print_r($error);
16         echo "</pre>";die;
17     }
18 }
19 
20 include "ceshi2.class.php";
21 ?>

 結果:

  3.3、set_exception_handler(exception_function)

 

參數 描述
error_function 必需。規定未捕獲的異常發生時調用的函數。
該函數必須在調用 set_exception_handler() 函數之前定義。
這個異常處理函數需要需要一個參數,即拋出的 exception 對象。

作用:

  set_exception_handler() 函數設置用戶自定義的異常處理函數。

  該函數用於創建運行時期間的用戶自己的異常處理方法。

  該函數會返回舊的異常處理程序,若失敗,則返回 null。

提示:在這個異常處理程序被調用后,腳本會停止執行。 

 eg.

 1 <?php
 2 // 第一種放方法
 3 // function myException($exception) {
 4 //     echo "<b>Exception:</b> " , $exception->getMessage();
 5 // }
 6 // set_exception_handler('myException');
 7  
 8 // 第二種方法
 9 class MyError{
10     //必須是靜態public方法
11     public static function myException($exception) {
12         echo "<b>Exception:</b> " , $exception->getMessage();
13     }
14 }
15 set_exception_handler(['MyError', 'myException']);
16 throw new Exception('Uncaught Exception occurred---沒有人處理的異常');

運行結果:

 

 作者:那一葉隨風

 原文地址:http://www.cnblogs.com/phpstudy2015-6/p/8433541.html

 聲明:本博客文章為原創,只代表本人在工作學習中某一時間內總結的觀點或結論。轉載時請在文章頁面明顯位置給出原文鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM