錯誤和異常的異同
"錯誤"和"異常"的概念十分相似,很容易混淆,"錯誤"和"異常"都表明了項目出了問題,都會提供相關的信息,並且都有錯誤類型。然而,"異常機制"是在"錯誤機制"後才出現的,"異常"是避免"錯誤"的不足。比較重要的一點就是因為"錯誤"的資訊不豐富,我們見過最多的函數說明就是: 成功時候返回***, 錯誤的時候返回FALSE, 然而一個函數出錯的原因可能有多種, 出錯的種類更有多種. 一個簡單的FALSE, 並不能把具體的錯誤訊息告訴呼叫者.
PHP中將程式碼自身異常(一般是環境或語法非法所致)成為錯誤,將運行中出現的邏輯錯誤稱為異常(Exception)錯誤是沒法通過程式碼處理的,而異常則可以透過try/catch處理.
異常
異常是Exception類別的對象,在遇到無法修復的狀況時拋出,出現問題時,異常用於主動出擊,委託職責,異常還可用於防守,預測潛在的問題,減輕其影響。
Exception物件有兩個主要的屬性:一個是訊息,另一個是數字程式碼。我們分別可以用getCode()和getMessage()來取得這兩個屬性。如下:
<?php $exception = new Exception("figthing!!!",100); $code = $exception->getCode();//100 $message = $exception->getMessage();//fight.....
拋出例外
當一個例外被拋出後程式碼會立即停止執行,其後的程式碼將不會繼續執行,PHP 會嘗試尋找符合的"catch"代碼塊。如果一個異常沒有被捕獲,而且又沒用使用set_exception_handler()作相應的處理的話,那麼 PHP 將會產生一個嚴重的錯誤,並且輸出未能捕獲異常(Uncaught Exception ...)的提示信息。
throw new Exception("this is a exception");//使用throw抛出异常
捕獲異常
我們應該捕獲拋出的異常並且使用優雅的方式處理。攔截並處理異常的方式是,把可能拋出異常的程式碼放到try/catch區塊中。並且如果使用多個catch攔截多個異常的時候,只會運行其中一個,如果PHP沒有找到合適的catch塊,異常會向上冒泡,直到PHP腳本由於致命錯誤而終止運行。如下:
try { throw new Exception("Error Processing Request"); $pdo = new PDO("mysql://host=wrong_host;dbname=wrong_name"); } catch (PDOException $e) { echo "pdo error!"; } catch(Exception $e){ echo "exception!"; }finally{ echo "end!";//finally是在捕获到任何类型的异常后都会运行的一段代码 }
运行结果:exception!end!
異常處理程序
那麼我們應該如何捕捉每個可能拋出的例外呢? PHP允許我們註冊一個全域異常處理程序,捕獲所有未被捕獲的異常。異常處理程序使用set_exception_handler()函式註冊(這裡使用匿名函式)。
set_exception_handler(function (Exception $e) { echo "我自己定义的异常处理".$e->getMessage(); }); throw new Exception("this is a exception"); //运行结果:我自己定义的异常处理this is a exception
錯誤
除了異常之外,PHP還提供了用於報告錯誤的函數。 PHP能觸發不同類型的錯誤,例如致命錯誤、執行階段錯誤、編譯時錯誤、啟動錯誤、使用者觸發的錯誤。可以在php.ini中設定錯誤報告方式(這裡不做多的解釋)
下面列舉一些錯誤報告層級:
值 常量 说明1 E_ERROR 报告导致脚本终止运行的致命错误2 E_WARNING 报告运行时的警告类错误(脚本不会终止运行)4 E_PARSE 报告编译时的语法解析错误8 E_NOTICE 报告通知类错误,脚本可能会产生错误32767 E_ALL 报告所有的可能出现的错误(不同的PHP版本,常量E_ALL的值也可能不同)
無論如何都必須遵守以下幾條規則:
一定要讓PHP報告錯誤
在開發環境中要顯示錯誤
在生產環境中不能顯示錯誤
在開發環境與生產環境中都要記錄錯誤
錯誤處理程序
與異常處理程序一樣,我們也可以使用set_error_handler()註冊全域錯誤處理程序,使用自己的邏輯方式攔截並處理PHP錯誤。我們要在錯誤處理程序中呼叫die()或exit()函數。如果不調用,PHP腳本會從出錯的地方繼續向下執行。如下:
set_error_handler(function ($errno,$errstr,$errfile,$errline)//常用的四个参数 { echo "错误等级:".$errno."<br>错误信息:".$errstr."<br>错误的文件名:".$errfile."<br>错误的行号:".$errline; exit(); }); trigger_error("this is a error");//自行触发的错误 echo '正常';
運行結果:
錯誤等級:1024
錯誤訊息:this is a error
錯誤的檔案名稱:/Users/toby/Desktop/www/Exception.php
錯誤的行號:33
相關的還有一個函數register_shutdown_function()---是一個會在php中止時執行的函數。 (有興趣的可以自行查詢一下)
錯誤轉換為異常
我們可以把PHP錯誤轉換為異常(並不是所有的錯誤都可以轉換,只能轉換php.ini文件中error_reporting指令設定的錯誤),使用處理異常的現有流程處理錯誤。這裡我們使用set_error_handler()函數將錯誤訊息託管至ErrorException(它是Exception的子類別),進而交給現有的例外系統處理。如下:
set_exception_handler(function (Exception $e) { echo "我自己定义的异常处理".$e->getMessage(); }); set_error_handler(function ($errno, $errstr, $errfile, $errline ) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline);//转换为异常 }); trigger_error("this is a error");//自行触发错误
運行結果:我自己定義的例外處理this is a error
PHP7的錯誤異常處理
PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出。
这种 Error 异常可以像 Exception 异常一样被第一个匹配的 try / catch 块所捕获。如果没有匹配的 catch 块,则调用异常处理函数(事先通过 set_exception_handler() 注册)进行处理。 如果尚未注册异常处理函数,则按照传统方式处理:被报告为一个致命错误(Fatal Error)。
Error 类并非继承自 Exception 类,所以不能用 catch (Exception $e) { ... } 来捕获 Error。你可以用 catch (Error $e) { ... },或者通过注册异常处理函数( set_exception_handler())来捕获 Error。
$a=1; try { $a->abc();//未定义此对象 } catch (Exception $e) { echo "error"; } catch (Error $e) { echo $e->getCode(); }
运行结果:0
PHP7 中出现了 Throwable 接口,该接口由 Error 和 Exception 实现,用户不能直接实现 Throwable 接口,而只能通过继承 Exception 来实现接口
try { // Code that may throw an Exception or Error. } catch (Throwable $t) { // Executed only in PHP 7, will not match in PHP 5.x } catch (Exception $e) { // Executed only in PHP 5.x, will not be reached in PHP 7 }
注意实际项目中,在开发环境中我们可以使用Whoops组件,在生产环境中我们可以使用Monolog组件。
相关推荐:
以上是PHP7錯誤和異常處理實例分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!