php異常與錯誤處理機(jī)制概念及使用介紹
基本概念
異常(exception)
程序執(zhí)行過程中,出現(xiàn)的不符預(yù)定業(yè)務(wù)邏輯和流程的,程序員可預(yù)測并提前寫好處理程序的一種情況
錯誤(error)
代碼本身的錯誤導(dǎo)致的程序運行失敗
標(biāo)準(zhǔn)異常處理
通過異常的定義,我們知道php中的異常是程序員提前預(yù)知并手動拋出的。
php通過try{}catch(){},配合Exception類,拋出并接收異常,實現(xiàn)異常的基本使用,如下
示例1
try{ $param = $_GET['param']; if(empty($param)) throw new Exception('非法參數(shù)'); //EmailException PhoneException 為自定義的異常類 if(empty($param['email'])) throw new EmailException('郵件為空'); if(empty($param['phone')) throw new PhoneException('手機(jī)號為空'); $last_number = $prams[10]; }catch(EmailException $e1){ echo $e1->getMessage();die(); }catch(PhoneException $e2){ echo $e2->getMessage();die(); }catch(Exception $e3){ echo $e3->getMessage();die(); }
自定義異常處理
當(dāng)代碼中有多處異常需要拋出時,我們可以不必每次都使用try…catch處理,完全可以統(tǒng)一處理。這時我們可以用set_exception_handler 方法,注冊一個異常監(jiān)聽方法。當(dāng)有異常拋出時,且沒有被 try … catch 捕獲處理的話,此時系統(tǒng)會檢查上下文是否注冊了 set_exception_handler。
如果未注冊 則進(jìn)入 PHP 標(biāo)準(zhǔn)錯誤處理 致命錯誤退出執(zhí)行。
如果已注冊 則進(jìn)入 set_exception_handler 處理 程序依然會退出執(zhí)行。
故建強(qiáng)烈議將需要后續(xù)處理的異常的執(zhí)行邏輯放入 try … catch 中執(zhí)行。
將會阻斷流程的異常使用set_exception_handler處理
// 捕獲異常后程序會退出執(zhí)行 set_exception_handler(function ($exception) { echo $exception->getMessage(); // 此處程序會退出執(zhí)行 異常到此結(jié)束 并不會交給 PHP 標(biāo)準(zhǔn)異常處理 }); throw new Exception('hello world!'); echo 'will i be executed?';
異常處理最佳使用場景
雖說異常是對不符合預(yù)期業(yè)務(wù)邏輯的處理,但并不是在所有業(yè)務(wù)流程判斷中都使用異常處理,這會導(dǎo)致代碼臃腫,那么什么時候使用異常處理最佳呢
控制異常代碼影響范圍
當(dāng)業(yè)務(wù)流程不在預(yù)期內(nèi)時,且會對后續(xù)代碼造成影響時。通過try…catch 及時拋出并處理異常,把異常造成的邏輯中斷破壞降低到最小范圍。上面實例代碼就是這種情況。
保證數(shù)據(jù)統(tǒng)一性
當(dāng)對相關(guān)聯(lián)的數(shù)據(jù)進(jìn)行操作,若有成功又失敗,會造成關(guān)聯(lián)數(shù)據(jù)之間的信息不同步。進(jìn)行該類操作時,一旦有一個數(shù)據(jù)操作失敗就拋出異常,然后把已操作的數(shù)據(jù)進(jìn)行回滾。
典型的使用案例就是對數(shù)據(jù)庫的事務(wù)操作,一般都放在try…catch中
錯誤處理
錯誤等級定義
php定義了一些錯誤等級常量,如下
名稱 | 值 | 說明 | 舉例 |
---|---|---|---|
E_ERROR | 1 | 致命的運行時錯誤(程序終止)。這類錯誤一般是不可恢復(fù)的情況,例如內(nèi)存分配導(dǎo)致的問題。后果是導(dǎo)致腳本終止不再繼續(xù)運行。 | 使用了未定義方法、類、方法參數(shù)不匹配等情況 |
E_WARNING | 2 | 運行時警告 (非致命錯誤)。僅給出提示信息,但是腳本不會終止運行。 | 除數(shù)為0等比較嚴(yán)重的錯誤 |
E_PARSE | 4 | 編譯時語法解析錯誤(程序終止)。解析錯誤僅僅由分析器產(chǎn)生 | 少了分號、括號等語法錯誤 |
E_NOTICE | 8 | 運行時通知。表示腳本遇到可能會表現(xiàn)為錯誤的情況,但是在可以正常運行的腳本里面也可能會有類似的通知。 | 使用了未定義的變量或不存在的偏移量 |
E_CORE_ERROR | 16 | 在PHP初始化啟動過程中發(fā)生的致命錯誤(程序終止)。該錯誤類似E_ERROR,但是是由PHP引擎核心產(chǎn)生的 | 例如php.ini文件配置錯誤 |
E_CORE_WARNING | 32 | PHP初始化啟動過程中發(fā)生的警告 (非致命錯誤) 。類似 E_WARNING,但是是由PHP引擎核心產(chǎn)生的 | 例如php.ini文件配置異常 |
E_COMPILE_ERROR | 64 | 致命編譯時錯誤(程序終止)。類似E_ERROR, 但是是由Zend腳本引擎產(chǎn)生的 | |
E_COMPILE_WARNING | 128 | 編譯時警告 (非致命錯誤)。類似 E_WARNING,但是是由Zend腳本引擎產(chǎn)生的 | |
E_USER_ERROR | 256 | 用戶產(chǎn)生的錯誤信息(程序終止)。類似 E_ERROR, 但是是由用戶自己在代碼中使用PHP函數(shù) trigger_error()來產(chǎn)生的 | |
E_USER_WARNING | 512 | 用戶產(chǎn)生的警告信息。類似 E_WARNING, 但是是由用戶自己在代碼中使用PHP函數(shù) trigger_error()來產(chǎn)生的 | |
E_USER_NOTICE | 1024 | 用戶產(chǎn)生的通知信息。類似 E_NOTICE, 但是是由用戶自己在代碼中使用PHP函數(shù) trigger_error()來產(chǎn)生的 | |
E_STRICT | 2048 | 啟用 PHP 對代碼的修改建議,以確保代碼具有最佳的互操作性和向前兼容性 | |
E_RECOVERABLE_ERROR | 4096 | 可被捕捉的致命錯誤。 它表示發(fā)生了一個可能非常危險的錯誤,但是還沒有導(dǎo)致PHP引擎處于不穩(wěn)定的狀態(tài)。 如果該錯誤沒有被用戶自定義句柄捕獲,將成為一個 E_ERROR 從而腳本會終止運行 | |
E_DEPRECATED | 8192 | 運行時通知。啟用后將會對在未來版本中可能無法正常工作的代碼給出警告 | |
E_USER_DEPRECATED | 16384 | 用戶產(chǎn)少的警告信息。 類似 E_DEPRECATED, 但是是由用戶自己在代碼中使用PHP函數(shù) trigger_error()來產(chǎn)生的 | |
E_ALL | 30719 | E_STRICT出外的所有錯誤和警告信息 |
經(jīng)常出現(xiàn)的錯誤提示一般是1,2,4,8幾種,E_CORE_*和E_CMMPILE_*級別的錯誤很少會出現(xiàn)
標(biāo)準(zhǔn)錯誤處理
標(biāo)準(zhǔn)錯誤處理是指針對程序執(zhí)行過程中出現(xiàn)的錯誤,用戶未自主處理時,php會使用標(biāo)準(zhǔn)模式展示這些錯誤
開啟標(biāo)準(zhǔn)錯誤提示
ini_set(‘display_errors’,‘on’); //off是關(guān)閉
設(shè)置標(biāo)準(zhǔn)錯誤提示等級
error_reporting(E_ALL | E_STRICT); //表示所有等級錯誤都為提示,可自行選擇需要提示的錯誤等級
默認(rèn)狀態(tài)下,php沒有開啟錯誤提示。當(dāng)有致命錯誤導(dǎo)致程序終止,且用戶也未捕獲錯誤時,會返回一個500錯誤
但當(dāng)開啟了標(biāo)準(zhǔn)錯誤提示后,會打印出錯誤信息
自主處理非致命錯誤
若我們想要自主捕獲錯誤并處理,可以使用set_error_handler方法,注冊一個處理錯誤的方法,如下
set_error_handler(function ($error_no, $error_msg, $error_file, $error_line) { //方法內(nèi)可以自行處理要打印的異常信息 echo '這是一個自主處理的異常,異常編號:'.$error_no; // 若return false,程序不會終止,錯誤會繼續(xù)遞交給 PHP 標(biāo)準(zhǔn)錯誤處理。否則結(jié)束程序 //return false; })
使用自定義錯誤處理的話,標(biāo)準(zhǔn)錯誤無效,因我們注冊的方法接管了標(biāo)準(zhǔn)錯誤處理
但是,set_error_handler并不能捕獲所有錯誤
- 可以捕獲: E_WARNING & E_NOTICE & E_DEPRCATED & E_USER_* & 部分 E_STRICT 級的錯誤。
- 無法捕獲: E_ERROR & E_PARSE & E_CORE_* & E_COMPLIE_* 級的錯誤。
自主處理致命錯誤
那么我們該如何獲取致命級別的錯誤呢
如果我們跟著文章設(shè)置了標(biāo)準(zhǔn)錯誤,并編寫代碼測試后,會發(fā)現(xiàn)當(dāng)代碼有致命錯誤時,并沒錯誤輸出,而是直接500錯誤,如下,我們新建一個error.php文件
<?php ini_set('display_errors','off'); error_reporting(E_ALL | E_STRICT); echo "aaa"
代碼少了分號,語法錯誤。當(dāng)時直接返回500,這是為什么呢。這個涉及到了php的程序的編譯和執(zhí)行問題
PHP是腳本語言,在執(zhí)行代碼時需要先進(jìn)行一系列的編譯處理,才能執(zhí)行。在文件編譯階段,對代碼語法進(jìn)行了校驗,但這個時候代碼未執(zhí)行,所以文件開頭的動態(tài)配置是沒有意義的。編譯時判斷語法錯誤,腳本直接停止了運行。直接調(diào)用了php.ini的默認(rèn)配置,不顯示錯誤信息。這就是為什么在php.ini配置可以生效,動態(tài)配置無效的原因。
為了解決這個問題,我們要保設(shè)置證標(biāo)準(zhǔn)錯誤開啟的文件正確,能夠被正常編譯執(zhí)行,配置才能生效。
我們包error.php最后一行代碼刪除。然后新建一個index.php文件,在文件中引入error.php即可,如下
index.php
<?php include "error.php"; echo "aaa"
再次執(zhí)行后,頁面輸出了錯誤信息。
這是因為index.php文件在編譯到錯誤代碼報錯前,先編譯了引入的error.php文件,error文件被正確執(zhí)行,配置生效。
根據(jù)php這個特性,我們要捕獲致命級錯誤,就需要捕獲錯誤的代碼不會被錯誤代碼影響到。try…catch就是一個完美的無措容器,我們可以在try引入如錯誤代碼(不能直接寫錯誤代碼,會編譯錯誤),在catch中捕獲錯誤,如下
try{ include 'index.php'; } catch (\ErrorException $errorException) { // 捕獲錯誤異常 echo 'ErrorException: ' . $errorException . PHP_EOL; } catch (\Exception $exception) { // 捕獲異常 echo 'Exception: ' . $exception . PHP_EOL; } catch (\TypeError $typeError) { // 捕獲類型錯誤 返回值/參數(shù)不正確 //var_dump($typeError); echo 'Type Error: ' . $typeError->getFile() . PHP_EOL; } catch (\ParseError $parseError) { // 捕獲解析錯誤 語法錯誤 echo 'Parse Error: ' . $parseError . PHP_EOL; } catch (\DivisionByZeroError $divisionByZeroError) { // 除 0 無法捕獲 但 除 0 取余可以捕獲 = = 很無奈 echo 'Division By Zero Error: ' . $divisionByZeroError . PHP_EOL; } catch (\Error $error) { // 基本錯誤 echo 'Error: ' . $error . PHP_EOL; }
拋出自定義錯誤
trigger_error 用來觸發(fā)用戶級別的自定義錯誤
set_error_handler 和 標(biāo)準(zhǔn)錯誤 都能捕獲到該錯誤
trigger("報錯信息",E_USER_NOTICE);//默認(rèn)錯誤等級為E_USER_NOTICE
支持E_USER_NOTICE,E_USER_WARNING,E_USER_DEPRECATED,E_USER_ERROR 四個錯誤類型的拋出
E_USER_ERROR 級別的錯誤如果被 PHP 標(biāo)準(zhǔn)錯誤處理 捕獲,腳本也會退出執(zhí)行
到此這篇關(guān)于php異常與錯誤處理機(jī)制概念及使用介紹的文章就介紹到這了,更多相關(guān)php異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
讓你的WINDOWS同時支持MYSQL4,MYSQL4.1,MYSQL5X
讓你的WINDOWS同時支持MYSQL4,MYSQL4.1,MYSQL5X...2006-12-12PHP n個不重復(fù)的隨機(jī)數(shù)生成代碼
PHP n個不重復(fù)的隨機(jī)數(shù)生成代碼,原理就是將數(shù)組順序隨即打亂 ,然取該數(shù)組中的某一段2009-06-06php找出指定范圍內(nèi)回文數(shù)且平方根也是回文數(shù)的方法
這篇文章主要介紹了php找出指定范圍內(nèi)回文數(shù)且平方根也是回文數(shù)的方法,實例分析了php判斷回文的技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-03-03PHP自定義函數(shù)實現(xiàn)數(shù)組比較功能示例
這篇文章主要介紹了PHP自定義函數(shù)實現(xiàn)數(shù)組比較功能,涉及php針對數(shù)組的遍歷、比較、判斷等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10在任意字符集下正常顯示網(wǎng)頁的方法二(續(xù))
在任意字符集下正常顯示網(wǎng)頁的方法二(續(xù))...2007-04-04