這篇文章要跟大家介紹PHP7使用set_error_handler和set_exception_handler處理異常機制的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。
由於歷史原因,php一開始被設計為一門面向過程的語言,所以異常處理沒有使用像Java一樣的try / catch 機制,出錯時直接顯示到頁面上,或記錄到web伺服器的錯誤日誌中,並且php的錯誤分成了很多的級別,例如E_ERROR、E_WARNING、E_PARSE、E_NOTICE等等,對於像E_ERROR、E_PARSE這樣的嚴重錯誤,php會直接終止腳本的運行。
雖然對於php5版本,我們可以使用set_error_handler來註冊自己的錯誤處理方法來代替php的標準錯誤處理方式(輸出到頁面或記錄到日誌),但是一些嚴重錯誤是無法通過這種方式來處理的,具體我們來看手冊對此方法的介紹:
mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] ) 设置一个用户的函数(error_handler)来处理脚本中出现的错误。 本函数可以用你自己定义的方式来处理运行中的错误, 例如,在应用程序中严重错误发生时,或者在特定条件下触发了一个错误(使用 trigger_error()),你需要对数据/文件做清理回收。 重要的是要记住 error_types 里指定的错误类型都会绕过 PHP 标准错误处理程序, 除非回调函数返回了 FALSE。 error_reporting() 设置将不会起到作用而你的错误处理函数继续会被调用 —— 不过你仍然可以获取 error_reporting 的当前值,并做适当处理。 需要特别注意的是带 @ error-control operator 前缀的语句发生错误时,这个值会是 0。 同时注意,在需要时你有责任使用 die()。 如果错误处理程序返回了,脚本将会继续执行发生错误的后一行。 以下级别的错误不能由用户定义的函数来处理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT。
手冊上說的很清楚,對於E_ERROR、E_PARSE之類的錯誤並不能被用戶處理,我們來看代碼演示(以下範例用php5.6運行)
<?php //自定义的错误处理方法 function _error_handler($errno, $errstr ,$errfile, $errline) { echo "错误编号errno: $errno<br>"; echo "错误信息errstr: $errstr<br>"; echo "出错文件errfile: $errfile<br>"; echo "出错行号errline: $errline<br>"; } set_error_handler('_error_handler', E_ALL | E_STRICT); // 注册错误处理方法来处理所有错误 echo $foo['bar']; // 由于数组未定义,会产生一个notice级别的错误
運行結果:
错误编号errno: 8 错误信息errstr: Undefined variable: foo 出错文件errfile: D:\project\demo\demo.php 出错行号errline: 16
這時錯誤訊息並沒有像往常一樣直接輸出到頁面上,而是按照我們自己的方式來處理了,如果不使用set_error_handler函數,錯誤訊息會是常見的這樣展示,當然我們可以關閉掉php的錯誤顯示,這樣錯誤就不會直接顯示到頁面上了。
Notice: Undefined variable: foo in D:\project\demo\demo.php on line 15
這樣的處理機制看似也還不錯,但上面提到不是所有錯誤都可以這樣處理,修改一下上面的程式碼如下:
<?php //自定义的错误处理方法 function _error_handler($errno, $errstr ,$errfile, $errline) { echo "错误编号errno: $errno<br>"; echo "错误信息errstr: $errstr<br>"; echo "出错文件errfile: $errfile<br>"; echo "出错行号errline: $errline<br>"; } set_error_handler('_error_handler', E_ALL | E_STRICT); // 注册错误处理方法来处理所有错误 echo $foo['bar']; // 由于数组未定义,会产生一个notice级别的错误 trigger_error('人为触发一个错误', E_USER_ERROR); //人为触发错误 foobar(3, 5); //调用未定义的方法将会产生一个Error级别的错误
再來運行:
错误编号errno: 8 错误信息errstr: Undefined variable: foo 出错文件errfile: D:\project\demo\demo.php 出错行号errline: 15 错误编号errno: 256 错误信息errstr: 人为产生触发一个错误 出错文件errfile: D:\project\demo\demo.php 出错行号errline: 17 Fatal error: Call to undefined function foobar() in D:\project\demo\demo.php on line 19
正如我們所料,前兩個錯誤被我們「捕獲」處理了,而最後的Fatal error並沒有按照我們註冊的錯誤函數來處理,還是使用的預設的處理方式,這也是php5版本的錯誤處理的一大缺陷。 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。
php7的這種錯誤處理機制有像java學習的意味,這樣使得我們可以自己來處理大多數的異常,下面看程式碼範例(以下程式碼使用php7運行)
<?php //自定义的错误处理方法 function _error_handler($errno, $errstr ,$errfile, $errline) { echo "错误编号errno: $errno<br>"; echo "错误信息errstr: $errstr<br>"; echo "出错文件errfile: $errfile<br>"; echo "出错行号errline: $errline<br>"; } set_error_handler('_error_handler', E_ALL | E_STRICT); // 注册错误处理方法来处理所有错误 try { echo $foo['bar']; // 由于数组未定义,会产生一个notice级别的错误 trigger_error('人为产生触发一个错误', E_USER_ERROR); //人为触发错误 foobar(3, 5); //调用未定义的方法将会产生一个Error级别的错误 } catch (Error $e) { echo "Error code: " . $e->getCode() . '<br>'; echo "Error message: " . $e->getMessage() . '<br>'; echo "Error file: " . $e->getFile() . '<br>'; echo "Error fileline: " . $e->getLine() . '<br>'; }
運行結果:
错误编号errno: 8 错误信息errstr: Undefined variable: foo 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 17 错误编号errno: 256 错误信息errstr: 人为产生触发一个错误 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 19 Error code: 0 Error message: Call to undefined function foobar() Error file: E:\project\demo\demo.php Error fileline: 21
這樣不同類型的錯誤都可以被我們自己處理了,包括致命錯誤。如果不使用 try / catch , php7的報錯訊息和php5還是有一些不同:
错误编号errno: 8 错误信息errstr: Undefined variable: foo 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 17 错误编号errno: 256 错误信息errstr: 人为触发一个错误 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 19 Fatal error: Uncaught Error: Call to undefined function foobar() in E:\project\demo\demo.php:21 Stack trace: #0 {main} thrown in E:\project\demo\demo.php on line 21
致命錯誤的描述變成: 拋出的一個Error沒有被捕獲。
注意這裡的catch限定的只能捕獲Error類的錯誤,並且手冊上明確說了Error類並不是Exception類的子類,那我同時想捕獲代碼中的Exception錯誤不是做不到了嗎,請看程式碼:
<?php //自定义的错误处理方法 function _error_handler($errno, $errstr ,$errfile, $errline) { echo "错误编号errno: $errno<br>"; echo "错误信息errstr: $errstr<br>"; echo "出错文件errfile: $errfile<br>"; echo "出错行号errline: $errline<br>"; } set_error_handler('_error_handler', E_ALL | E_STRICT); // 注册错误处理方法来处理所有错误 try { echo $foo['bar']; // 由于数组未定义,会产生一个notice级别的错误 trigger_error('人为触发一个错误', E_USER_ERROR); //人为触发错误 throw new Exception('This is a exception', 400); //抛出一个Exception,看是否可以被catch foobar(3, 5); //调用未定义的方法将会产生一个Error级别的错误 } catch (Error $e) { echo "Error code: " . $e->getCode() . '<br>'; echo "Error message: " . $e->getMessage() . '<br>'; echo "Error file: " . $e->getFile() . '<br>'; echo "Error fileline: " . $e->getLine() . '<br>'; }
執行結果:
错误编号errno: 8 错误信息errstr: Undefined variable: foo 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 17 错误编号errno: 256 错误信息errstr: 人为触发一个错误 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 19 Fatal error: Uncaught Exception: This is a exception in E:\project\demo\demo.php:21 Stack trace: #0 {main} thrown in E:\project\demo\demo.php on line 21
那有沒有什麼辦法呢,其實看手冊上的繼承關係圖
可以看出,Error類別和Exception類別都是Throwable的子類別(其實是Error類別和Exception類別都實作了Throwable介面),所以上面的程式碼可以優化為:
<?php //自定义的错误处理方法 function _error_handler($errno, $errstr ,$errfile, $errline) { echo "错误编号errno: $errno<br>"; echo "错误信息errstr: $errstr<br>"; echo "出错文件errfile: $errfile<br>"; echo "出错行号errline: $errline<br>"; } set_error_handler('_error_handler', E_ALL | E_STRICT); // 注册错误处理方法来处理所有错误 try { echo $foo['bar']; // 由于数组未定义,会产生一个notice级别的错误 trigger_error('人为触发一个错误', E_USER_ERROR); //人为触发错误 if (mt_rand(1, 10) > 5) { throw new Exception('This is a exception', 400); //抛出一个Exception,看是否可以被catch } else { foobar(3, 5); //调用未定义的方法将会产生一个Error级别的错误 } } catch (Throwable $e) { echo "Error code: " . $e->getCode() . '<br>'; echo "Error message: " . $e->getMessage() . '<br>'; echo "Error file: " . $e->getFile() . '<br>'; echo "Error fileline: " . $e->getLine() . '<br>'; }
多次運行可以看到,不管是Exception異常還是Error異常,都可以被捕獲處理了。
如果不想所有的錯誤都用try / catch 處理,還可以使用set_exception_handler註冊異常處理函數,這樣當有未被catch的異常產生時,系統會為我們自動呼叫註冊的處理函數來處理。
<?php //自定义的错误处理方法 function _error_handler($errno, $errstr ,$errfile, $errline) { echo "错误编号errno: $errno<br>"; echo "错误信息errstr: $errstr<br>"; echo "出错文件errfile: $errfile<br>"; echo "出错行号errline: $errline<br>"; } set_error_handler('_error_handler', E_ALL | E_STRICT); // 注册错误处理方法来处理所有错误 function _exception_handler(Throwable $e) { if ($e instanceof Error) { echo "catch Error: " . $e->getCode() . ' ' . $e->getMessage() . '<br>'; } else { echo "catch Exception: " . $e->getCode() . ' ' . $e->getMessage() . '<br>'; } } set_exception_handler('_exception_handler'); // 注册异常处理方法来捕获异常 echo $foo['bar']; // 由于数组未定义,会产生一个notice级别的错误 trigger_error('人为触发一个错误', E_USER_ERROR); //人为触发错误 if (mt_rand(1, 10) > 5) { throw new Exception('This is a exception', 400); //抛出一个Exception,看是否可以被catch } else { foobar(3, 5); //调用未定义的方法将会产生一个Error级别的错误 }
错误编号errno: 8 错误信息errstr: Undefined variable: foo 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 29 错误编号errno: 256 错误信息errstr: 人为触发一个错误 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 31 catch Error: 0 Call to undefined function foobar() 错误编号errno: 8 错误信息errstr: Undefined variable: foo 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 29 错误编号errno: 256 错误信息errstr: 人为触发一个错误 出错文件errfile: E:\project\demo\demo.php 出错行号errline: 31 catch Exception: 400 This is a exception
這時我們可能又會被PHP7弄暈,哪些被set_error_handler處理,哪些被set_exception_handler處理,手冊上也沒有明確說明這塊,根據我的總結,大致上不會導致腳本終止運行的錯誤會被set_error_handler處理,而會終止腳本運行的嚴重錯誤會被當作Error拋出,但不是絕對,上面人為觸發的
E_USER_ERROR就是一個會打斷腳本運行的錯誤,但是併沒有當作Error異常拋出,而是交由set_error_handler註冊的方法處理,這可能是因為這類錯誤是我們自己人為產生的有關,所以PHP7的錯誤處理還是有一些含糊不清,對於我們自己處理時要多加小心。
推薦學習:php影片教學
以上是PHP7如何使用set_error_handler和set_exception_handler處理異常機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!