摘要:又或者反過(guò)來(lái),把錯(cuò)誤當(dāng)成異常來(lái)處理。當(dāng)然,我猜它的目的,應(yīng)該也是為了能實(shí)現(xiàn)錯(cuò)誤與異常之間優(yōu)雅轉(zhuǎn)換而添加的。至此,錯(cuò)誤與異常的學(xué)習(xí)基本完畢。
這話(huà)題已經(jīng)沒(méi)有什么新意了,這里只是做做筆記,作為思路的一種整理,也以便后續(xù)忘了可以回來(lái)這里查找。
錯(cuò)誤以下是 PHP 最常見(jiàn)的幾種錯(cuò)誤:
// E_NOTICE echo $a; // E_WARNING echo 100 / 0; class Sample { public function method() { //not static method } } // E_STRICT Sample::method(); // E_ERROR new Dummy();
運(yùn)行上面代碼,頁(yè)面輸出以下信息:
Notice: Undefined variable: a in D:errors-exceptionsdemo4.php on line 6 Warning: Division by zero in D:errors-exceptionsdemo4.php on line 9 Strict Standards: Non-static method Sample::method() should not be called statically in D:errors-exceptionsdemo4.php on line 20 Fatal error: Class "Dummy" not found in D:errors-exceptionsdemo4.php on line 23
在生產(chǎn)環(huán)境下,是不允許把錯(cuò)誤信息輸出到頁(yè)面的。
怎么辦?關(guān)閉錯(cuò)誤輸出
ini_set("display_errors", 0);
此時(shí),刷新頁(yè)面,頁(yè)面將不會(huì)報(bào)任何錯(cuò)誤。頁(yè)面一片空白,或者顯示 500 錯(cuò)誤。
這也不是我們希望的,雖然不把錯(cuò)誤輸出到頁(yè)面,但是這些錯(cuò)誤我們是希望把它們都收集起來(lái),寫(xiě)到日志里面,以便開(kāi)發(fā)人員能夠不斷改進(jìn)代碼,排查錯(cuò)誤。
怎么辦?自定義錯(cuò)誤處理
set_error_handler(function($errno, $errstr, $errfile, $errline) { //在這里對(duì)錯(cuò)誤進(jìn)行處理 echo $errstr . "
"; });
運(yùn)行上面的代碼,頁(yè)面輸出:
Undefined variable: a Division by zero Non-static method Sample::method() should not be called statically
很奇怪,不是應(yīng)該輸出 4 個(gè)錯(cuò)誤嗎?怎么 Fatal error 沒(méi)有捕捉到。查看 set_error_handler 幫助文檔,我們發(fā)現(xiàn),它有以下描述:
以下級(jí)別的錯(cuò)誤不能由用戶(hù)定義的函數(shù)來(lái)處理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 調(diào)用 set_error_handler() 函數(shù)所在文件中產(chǎn)生的大多數(shù) E_STRICT。
噢~,原來(lái)是這樣,原來(lái) set_error_handler 方法是不能捕捉 E_ERROR 錯(cuò)誤的(上面的 Fatal error)。那么這類(lèi)錯(cuò)誤,我們是不能放過(guò)的,也必須捕捉到,并做適當(dāng)?shù)奶幚怼?/p>
怎么辦? 利用 register_shutdown_function 函數(shù)
register_shutdown_function(function() { if(is_null($e = error_get_last()) === false) { echo $e["message"] . "
"; } });
此時(shí),再運(yùn)行上面的例子,頁(yè)面會(huì)輸出:
Undefined variable: a Division by zero Non-static method Sample::method() should not be called statically Class "Dummy" not found
很好,四種錯(cuò)誤,我們都成功捕捉了,并按照我們自己的方式進(jìn)行了輸出。
到目前為止,應(yīng)該說(shuō)能捕捉的 PHP 錯(cuò)誤,我們都捕捉到了,當(dāng)然還有一些錯(cuò)誤,壓根就沒(méi)有辦法捕捉。比如語(yǔ)法錯(cuò)誤,這類(lèi)錯(cuò)誤是在 PHP 引擎對(duì)即將執(zhí)行的文件編譯期間的錯(cuò)誤。
像上面這種錯(cuò)誤,程序就沒(méi)有辦法捕捉了。只要程序是經(jīng)過(guò)測(cè)試的,一般不會(huì)在生產(chǎn)環(huán)境出現(xiàn)此類(lèi)錯(cuò)誤,所以也不用過(guò)于但心。
最后注:register_shutdown_function 函數(shù)會(huì)在任何導(dǎo)致頁(yè)面退出的時(shí)候,會(huì)被調(diào)用。比如發(fā)生了致命錯(cuò)誤、使用 exit() 函數(shù)、又或者是頁(yè)面執(zhí)行完畢了,都會(huì)觸發(fā)該函數(shù)。利用這個(gè)特征,我們可以在頁(yè)面退出時(shí),獲取到最后一個(gè)錯(cuò)誤,然后進(jìn)行記錄。這個(gè)的 “最后一個(gè)錯(cuò)誤” 往往是致命錯(cuò)誤,原因很簡(jiǎn)單:因?yàn)橐坏╁e(cuò)誤被 set_error_handler 捕捉到了,那么 register_shutdown_function 將捕捉不了。而 前者捕捉不了的,才會(huì)被后者捕捉。
異常在 PHP 中,所以異常的基類(lèi)都是 Exception。異常應(yīng)該說(shuō)是在 PHP 后來(lái)引入了面向?qū)ο蟮母拍詈?,才有的產(chǎn)物。那么說(shuō),PHP 原來(lái)只拋錯(cuò)誤,卻沒(méi)有異常的概念了。但現(xiàn)在,異常的使用已經(jīng)非常廣泛了,我們有必要學(xué)習(xí)一下。
好,我們來(lái)制造一些異常:
new PDO("mysql:dbname=testdb;host=127.0.0.1", "root", "wrong_passwd"); //運(yùn)行結(jié)果 Fatal error: Uncaught exception "PDOException" with message "SQLSTATE[HY000] [1045] Access denied for user "root"@"localhost" (using password: YES)" in D:errors-exceptionsdemo6.php:6 Stack trace: #0 D:errors-exceptionsdemo6.php(6): PDO->__construct("mysql:dbname=te...", "root", "wrong_passwd") #1 {main} thrown in D:errors-exceptionsdemo6.php on line 6再制造一個(gè):
throw new Exception("我是異常"); //運(yùn)行結(jié)果 Fatal error: Uncaught exception "Exception" with message "我是異常" in D:errors-exceptionsdemo6.php:9 Stack trace: #0 {main} thrown in D:errors-exceptionsdemo6.php on line 9在生產(chǎn)環(huán)境下,頁(yè)面直接輸出這些異常,同樣是不優(yōu)雅的,那么我們同樣可以像關(guān)閉錯(cuò)誤輸出一樣,關(guān)閉異常的輸出:
ini_set("display_errors", 0);同樣地,異常雖然不顯示出來(lái)了,但是我們需要記錄并處理這些異常。
怎樣做? 使用 set_exception_handler 函數(shù)
set_exception_handler(function($exception) { //在這里,統(tǒng)一處理異常 echo get_class($exception) .": ". $exception->getMessage(); });此時(shí),再運(yùn)行頁(yè)面,會(huì)輸出以下信息:
PDOException: SQLSTATE[HY000] [1045] Access denied for user "root"@"localhost" (using password: YES)小結(jié)在我剛開(kāi)始學(xué)習(xí) PHP 的時(shí)候,的確被它的錯(cuò)誤和異常困擾了許久。最開(kāi)始,我甚至不會(huì)用異常。實(shí)際上,在現(xiàn)代的 PHP 里面,我們基本上可以完全控制它的異常和錯(cuò)誤。只需要分開(kāi)處理就可以了。
擴(kuò)展:我們?cè)趯?shí)際項(xiàng)目中捕捉并處理異常和錯(cuò)誤的時(shí)候,往往是把兩者合二為一。就是說(shuō)把異常也當(dāng)成錯(cuò)誤來(lái)處理。又或者反過(guò)來(lái),把錯(cuò)誤當(dāng)成異常來(lái)處理。
下面,就讓我們一起看看,如何把兩者相互轉(zhuǎn)換:
把異常轉(zhuǎn)換為錯(cuò)誤處理
"; } //自定義異常處理 function exceptionHandler($exception) { errorHandler( $exception->getCode(), $exception->getMessage(), $exception->getFile(), $exception->getLine() ); } //自定義致命錯(cuò)誤處理 function shutdownHandler() { if(is_null($e = error_get_last()) === false) { errorHandler( $e["type"], $e["message"], $e["file"], $e["line"] ); } }不過(guò)這樣處理法,會(huì)導(dǎo)致異常的堆棧信息“丟失”,意思是無(wú)法處理這些堆棧信息了。當(dāng)然是有辦法處理的了,具體請(qǐng)看 demo3.php。
再看看,如何把錯(cuò)誤轉(zhuǎn)換為異常 (注意:以下代碼僅為了演示其原理,代碼本身并非完全合理):
set_error_handler("errorHandler"); function errorHandler($errno, $errstr, $errfile, $errline) { throw new ErrorException($errstr, $errno, 0, $errfile, $errline); };大家看到,我們使用了 ErrorException 這個(gè)類(lèi),這是 PHP 后來(lái)才引入的,叫作錯(cuò)誤異常。當(dāng)然,我猜它的目的,應(yīng)該也是為了能實(shí)現(xiàn)錯(cuò)誤與異常之間優(yōu)雅轉(zhuǎn)換而添加的。
至此,錯(cuò)誤與異常的學(xué)習(xí)基本完畢。最后推薦看看一個(gè)網(wǎng)站有關(guān)于對(duì) PHP 錯(cuò)誤與異常的介紹,尤其是對(duì)異常的一些行為的說(shuō)明,都是值得注意的,網(wǎng)站在這里:PHP - Error & Exception Handling
參考文獻(xiàn)PHP在什么時(shí)候應(yīng)該使用異常處理(Exception)?
PHP Trick: Catching fatal errors (E_ERROR) with a custom error handler
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/30299.html
摘要:處理異常是編程非常重要的一點(diǎn)。我們的程序依賴(lài)于第三方服務(wù)數(shù)據(jù)庫(kù)以及我們的用戶(hù),一切都不可預(yù)料。為了處理這些錯(cuò)誤,需要添加一個(gè)中間件,它有個(gè)參數(shù)這樣,我們就可以使用中間件統(tǒng)一處理錯(cuò)誤了。 譯者按:根據(jù)墨菲定律:有可能出錯(cuò)的事情,就會(huì)出錯(cuò)。那么,既然代碼必然會(huì)出錯(cuò),我們就應(yīng)該處理好異常。 原文: How to handle errors in Express 譯者:Fundebug ...
摘要:一旦異常被拋出,就表明錯(cuò)誤已無(wú)法挽回,也不能回來(lái)繼續(xù)執(zhí)行。這種在編譯時(shí)被強(qiáng)制檢查的異常稱(chēng)為被檢查的異常。通過(guò)獲取原始異常。構(gòu)造器對(duì)于在構(gòu)造階段可能會(huì)拋出異常,并要求清理的類(lèi),最安全的做法是使用嵌套的子句。 點(diǎn)擊進(jìn)入我的博客 Java異常處理的目的在于通過(guò)使用少于目前數(shù)量的代碼來(lái)簡(jiǎn)化大型、可靠的程序的生成,并且通過(guò)這種方式可以使你更自信:你的應(yīng)用中沒(méi)有未處理的錯(cuò)誤。 12.1 概念 異...
摘要:當(dāng)運(yùn)行時(shí)系統(tǒng)遍歷調(diào)用棧而未找到合適的異常處理器,則運(yùn)行時(shí)系統(tǒng)終止。不可查異常編譯器不要求強(qiáng)制處置的異常包括運(yùn)行時(shí)異常與其子類(lèi)和錯(cuò)誤。 目錄介紹 1.什么是異常 2.異常 2.1 異常的概述和分類(lèi)【了解】 2.2 JVM默認(rèn)是如何處理異常的【理解】 2.3 異常處理的兩種方式【理解】 2.4 try...catch的方式處理異?!菊莆铡?2.5 編譯期異常和運(yùn)行期異常的區(qū)別【理解】...
摘要:對(duì)異常的處理方法是打印異常的跟蹤棧信息并終止程序運(yùn)行。應(yīng)盡量對(duì)異常進(jìn)行適當(dāng)?shù)奶幚?,而不是?jiǎn)單的將異常跟蹤棧信息打印出來(lái)。 一、異常概述 開(kāi)發(fā)者都希望所有錯(cuò)誤都能在編譯階段被發(fā)現(xiàn),就是試圖在運(yùn)行程序之前排除所有錯(cuò)誤,但這是不現(xiàn)實(shí)的,余下問(wèn)題必須在運(yùn)行期間得到解決。 Java將異常分為兩種:CheckedException和RuntimeException。其中,CheckedExcept...
摘要:異常異常的概述和分類(lèi)異常的概述異常就是程序在運(yùn)行過(guò)程中出現(xiàn)的錯(cuò)誤。運(yùn)行時(shí)異常就是程序員所犯的錯(cuò)誤,需要回來(lái)修改代碼。獲取異常類(lèi)名和異常信息,返回字符串。如果路徑名不同,就是改名并剪切。刪除注意事項(xiàng)中的刪除不走回收站。 1_異常(異常的概述和分類(lèi)) A:異常的概述 異常就是Java程序在運(yùn)行過(guò)程中出現(xiàn)的錯(cuò)誤。 B:異常的分類(lèi) 通過(guò)API查看Throwable Error 服務(wù)...
閱讀 2680·2021-11-25 09:43
閱讀 705·2021-11-12 10:36
閱讀 4879·2021-11-08 13:18
閱讀 2214·2021-09-06 15:00
閱讀 3161·2019-08-30 15:56
閱讀 978·2019-08-30 13:57
閱讀 2018·2019-08-30 13:48
閱讀 1442·2019-08-30 11:13