摘要:又或者反過來,把錯誤當成異常來處理。當然,我猜它的目的,應該也是為了能實現錯誤與異常之間優雅轉換而添加的。至此,錯誤與異常的學習基本完畢。
這話題已經沒有什么新意了,這里只是做做筆記,作為思路的一種整理,也以便后續忘了可以回來這里查找。
錯誤以下是 PHP 最常見的幾種錯誤:
// 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();
運行上面代碼,頁面輸出以下信息:
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
在生產環境下,是不允許把錯誤信息輸出到頁面的。
怎么辦?關閉錯誤輸出
ini_set("display_errors", 0);
此時,刷新頁面,頁面將不會報任何錯誤。頁面一片空白,或者顯示 500 錯誤。
這也不是我們希望的,雖然不把錯誤輸出到頁面,但是這些錯誤我們是希望把它們都收集起來,寫到日志里面,以便開發人員能夠不斷改進代碼,排查錯誤。
怎么辦?自定義錯誤處理
set_error_handler(function($errno, $errstr, $errfile, $errline) { //在這里對錯誤進行處理 echo $errstr . "
"; });
運行上面的代碼,頁面輸出:
Undefined variable: a Division by zero Non-static method Sample::method() should not be called statically
很奇怪,不是應該輸出 4 個錯誤嗎?怎么 Fatal error 沒有捕捉到。查看 set_error_handler 幫助文檔,我們發現,它有以下描述:
以下級別的錯誤不能由用戶定義的函數來處理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 調用 set_error_handler() 函數所在文件中產生的大多數 E_STRICT。
噢~,原來是這樣,原來 set_error_handler 方法是不能捕捉 E_ERROR 錯誤的(上面的 Fatal error)。那么這類錯誤,我們是不能放過的,也必須捕捉到,并做適當的處理。
怎么辦? 利用 register_shutdown_function 函數
register_shutdown_function(function() { if(is_null($e = error_get_last()) === false) { echo $e["message"] . "
"; } });
此時,再運行上面的例子,頁面會輸出:
Undefined variable: a Division by zero Non-static method Sample::method() should not be called statically Class "Dummy" not found
很好,四種錯誤,我們都成功捕捉了,并按照我們自己的方式進行了輸出。
到目前為止,應該說能捕捉的 PHP 錯誤,我們都捕捉到了,當然還有一些錯誤,壓根就沒有辦法捕捉。比如語法錯誤,這類錯誤是在 PHP 引擎對即將執行的文件編譯期間的錯誤。
像上面這種錯誤,程序就沒有辦法捕捉了。只要程序是經過測試的,一般不會在生產環境出現此類錯誤,所以也不用過于但心。
最后注:register_shutdown_function 函數會在任何導致頁面退出的時候,會被調用。比如發生了致命錯誤、使用 exit() 函數、又或者是頁面執行完畢了,都會觸發該函數。利用這個特征,我們可以在頁面退出時,獲取到最后一個錯誤,然后進行記錄。這個的 “最后一個錯誤” 往往是致命錯誤,原因很簡單:因為一旦錯誤被 set_error_handler 捕捉到了,那么 register_shutdown_function 將捕捉不了。而 前者捕捉不了的,才會被后者捕捉。
異常在 PHP 中,所以異常的基類都是 Exception。異常應該說是在 PHP 后來引入了面向對象的概念后,才有的產物。那么說,PHP 原來只拋錯誤,卻沒有異常的概念了。但現在,異常的使用已經非常廣泛了,我們有必要學習一下。
好,我們來制造一些異常:
new PDO("mysql:dbname=testdb;host=127.0.0.1", "root", "wrong_passwd"); //運行結果 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再制造一個:
throw new Exception("我是異常"); //運行結果 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在生產環境下,頁面直接輸出這些異常,同樣是不優雅的,那么我們同樣可以像關閉錯誤輸出一樣,關閉異常的輸出:
ini_set("display_errors", 0);同樣地,異常雖然不顯示出來了,但是我們需要記錄并處理這些異常。
怎樣做? 使用 set_exception_handler 函數
set_exception_handler(function($exception) { //在這里,統一處理異常 echo get_class($exception) .": ". $exception->getMessage(); });此時,再運行頁面,會輸出以下信息:
PDOException: SQLSTATE[HY000] [1045] Access denied for user "root"@"localhost" (using password: YES)小結在我剛開始學習 PHP 的時候,的確被它的錯誤和異常困擾了許久。最開始,我甚至不會用異常。實際上,在現代的 PHP 里面,我們基本上可以完全控制它的異常和錯誤。只需要分開處理就可以了。
擴展:我們在實際項目中捕捉并處理異常和錯誤的時候,往往是把兩者合二為一。就是說把異常也當成錯誤來處理。又或者反過來,把錯誤當成異常來處理。
下面,就讓我們一起看看,如何把兩者相互轉換:
把異常轉換為錯誤處理
"; } //自定義異常處理 function exceptionHandler($exception) { errorHandler( $exception->getCode(), $exception->getMessage(), $exception->getFile(), $exception->getLine() ); } //自定義致命錯誤處理 function shutdownHandler() { if(is_null($e = error_get_last()) === false) { errorHandler( $e["type"], $e["message"], $e["file"], $e["line"] ); } }不過這樣處理法,會導致異常的堆棧信息“丟失”,意思是無法處理這些堆棧信息了。當然是有辦法處理的了,具體請看 demo3.php。
再看看,如何把錯誤轉換為異常 (注意:以下代碼僅為了演示其原理,代碼本身并非完全合理):
set_error_handler("errorHandler"); function errorHandler($errno, $errstr, $errfile, $errline) { throw new ErrorException($errstr, $errno, 0, $errfile, $errline); };大家看到,我們使用了 ErrorException 這個類,這是 PHP 后來才引入的,叫作錯誤異常。當然,我猜它的目的,應該也是為了能實現錯誤與異常之間優雅轉換而添加的。
至此,錯誤與異常的學習基本完畢。最后推薦看看一個網站有關于對 PHP 錯誤與異常的介紹,尤其是對異常的一些行為的說明,都是值得注意的,網站在這里:PHP - Error & Exception Handling
參考文獻PHP在什么時候應該使用異常處理(Exception)?
PHP Trick: Catching fatal errors (E_ERROR) with a custom error handler
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30299.html
摘要:處理異常是編程非常重要的一點。我們的程序依賴于第三方服務數據庫以及我們的用戶,一切都不可預料。為了處理這些錯誤,需要添加一個中間件,它有個參數這樣,我們就可以使用中間件統一處理錯誤了。 譯者按:根據墨菲定律:有可能出錯的事情,就會出錯。那么,既然代碼必然會出錯,我們就應該處理好異常。 原文: How to handle errors in Express 譯者:Fundebug ...
摘要:一旦異常被拋出,就表明錯誤已無法挽回,也不能回來繼續執行。這種在編譯時被強制檢查的異常稱為被檢查的異常。通過獲取原始異常。構造器對于在構造階段可能會拋出異常,并要求清理的類,最安全的做法是使用嵌套的子句。 點擊進入我的博客 Java異常處理的目的在于通過使用少于目前數量的代碼來簡化大型、可靠的程序的生成,并且通過這種方式可以使你更自信:你的應用中沒有未處理的錯誤。 12.1 概念 異...
摘要:對異常的處理方法是打印異常的跟蹤棧信息并終止程序運行。應盡量對異常進行適當的處理,而不是簡單的將異常跟蹤棧信息打印出來。 一、異常概述 開發者都希望所有錯誤都能在編譯階段被發現,就是試圖在運行程序之前排除所有錯誤,但這是不現實的,余下問題必須在運行期間得到解決。 Java將異常分為兩種:CheckedException和RuntimeException。其中,CheckedExcept...
摘要:異常異常的概述和分類異常的概述異常就是程序在運行過程中出現的錯誤。運行時異常就是程序員所犯的錯誤,需要回來修改代碼。獲取異常類名和異常信息,返回字符串。如果路徑名不同,就是改名并剪切。刪除注意事項中的刪除不走回收站。 1_異常(異常的概述和分類) A:異常的概述 異常就是Java程序在運行過程中出現的錯誤。 B:異常的分類 通過API查看Throwable Error 服務...
閱讀 2650·2021-11-25 09:43
閱讀 670·2021-11-12 10:36
閱讀 4615·2021-11-08 13:18
閱讀 2168·2021-09-06 15:00
閱讀 3106·2019-08-30 15:56
閱讀 924·2019-08-30 13:57
閱讀 1985·2019-08-30 13:48
閱讀 1413·2019-08-30 11:13