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