淺談PHP異常處理

一、PHP中異常的獨特性

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

  PHP中的異常:html

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

  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 }

結果:測試

結果顯示:編碼

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

結論:
  PHP一般是沒法自動捕獲有意義的異常,它把全部不正常的狀況都視做了錯誤,你要想捕獲異常就得使用if....else結構,保證代碼是正常的,而後判斷進行手動拋出異常。

二、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()進行設置。

 

三、PHP中的異常處理

  3.一、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.二、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.三、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

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

相關文章
相關標籤/搜索