1、PHP的異常和錯誤php
異常:在程序運行中不符合預期的狀況及與正常流程不一樣的狀況。一種不正常的狀況,就是按照正常邏輯不應出錯,但任然出錯的狀況,這屬於邏輯和業務流程的一種中斷,而不是語法錯誤。PHP只有主動 throw 後,才能捕獲異常(通常狀況下是這樣,也有一些異常PHP能夠自動捕獲)html
錯誤:屬於自身問題,是一種非法語法或環境問題致使,讓編譯器沒法經過檢查甚至沒法運行的狀況。(簡單說就是使腳本運行不正常的狀況)程序員
2、錯誤的級別thinkphp
大體分爲幾類:數據庫
一、deprecated,最低級別的錯誤,表示「不推薦、不建議」。通常是因爲使用不推薦的、過期的函數或語法形成的。雖不會影響PHP正常流程,但通常狀況下建議修正。vim
二、notice,通常告訴你語法中存在不當的地方。如使用的變量未定義、數組索引是字符時沒有加引號,php視爲常量去查找,找不到再視爲變量。數組
不影響PHP正常流程。服務器
三、warning,比較高的錯誤,在語法中出現很不恰當的狀況下才報此錯誤,好比函數參數不匹配。這種級別的會致使得不到預期結果,故須要修改代碼。php7
四、fetal error,致命錯誤,直接致使PHP流程終結,後面的代碼再也不執行。好比調用一個不存在的方法,此錯誤必須處理。app
五、prase error,最高級別的錯誤,語法解析錯誤。屬於語法檢查階段錯誤,致使PHP沒法經過語法檢查。
PHP手冊中一共定義了16個級別的錯誤,最多見的就這幾個。
level 可能的值:
1 E_ERROR 致命的運行錯誤。錯誤沒法恢復,暫停執行腳本。 2 E_WARNING 運行時警告(非致命性錯誤)。非致命的運行錯誤,腳本執行不會中止。 4 E_PARSE 編譯時解析錯誤。解析錯誤只由分析器產生。 8 E_NOTICE 運行時提醒(這些常常是你代碼中的bug引發的,也多是有意的行爲形成的。)
16 E_CORE_ERROR PHP 啓動時初始化過程當中的致命錯誤。 32 E_CORE_WARNING PHP啓動時初始化過程當中的警告(非致命性錯)。
64 E_COMPILE_ERROR 編譯時致命性錯。這就像由Zend腳本引擎生成了一個E_ERROR。 128 E_COMPILE_WARNING 編譯時警告(非致性錯)。這就像由Zend腳本引擎生成了E_WARNING警告。
256 E_USER_ERROR 自定義錯誤消息。像用PHP函數trigger_error(程序員設置E_ERROR) 512 E_USER_WARNING 自定義警告消息。像用PHP函數trigger_error(程序員設的E_WARNING警告) 1024 E_USER_NOTICE 自定義的提醒消息。像由使用PHP函數trigger_error(程序員E_NOTICE集)
2048 E_STRICT 編碼標準化警告。容許PHP建議修改代碼以確保最佳的互操做性向前兼容性。 4096 E_RECOVERABLE_ERROR 開捕致命錯誤。像E_ERROR,但能夠經過用戶定義的處理捕獲(又見set_error_handler()) 8191 E_ALL 全部的錯誤和警告(不包括 E_STRICT) (E_STRICT will be part of E_ALL as of PHP 6.0) 16384 E_USER_DEPRECATED 30719 E_ALL
推薦博文:http://www.cnblogs.com/zyf-zhaoyafei/p/3649434.html
3、PHP中的錯誤處理機制
set_error_handler函數接管PHP錯誤處理,也可使用trigger_error函數主動拋出一個錯誤。
set_error_handler(error_function, error_types)
設置用戶自定義的錯誤處理函數。函數用於建立運行期間的用戶本身的錯誤處理方法。它須要先建立一個錯誤處理函數,而後設置錯誤級別。
參數描述:
error_function($errno, $errstr, $errfile, $errline):規定發生錯誤時運行的函數。必須。用戶的函數須要接受兩個參數:錯誤碼和描述錯誤的 string。另外有可能提供三個可選參數:發生錯誤的文件名、發生錯誤的行號 以及發生錯誤的上下文(一個指向錯誤發生時活動符號表的 array。
支持多種調用:
<?php // 直接傳函數名 NonClassFunction set_error_handler('function_name'); // 傳 class_name && function_name set_error_handler(array('class_name', 'function_name')); ?>
error_type:規定在哪一個錯誤報告級別會顯示用戶定義的錯誤。可選。默認是 E_ALL | E_STRICT。
注意:使用該函數會徹底繞過標準PHP錯誤處理函數(error_reporting(),包括@符),若是有必要,用戶定義的錯誤處理程序必須終止(die())腳本。若是在腳本執行前發生錯誤,因爲那時自定義程序尚未註冊,所以不會用到這個自定義錯誤處理程序。因此通常定義在開頭。且如下級別的錯誤不能由用戶定義的函數來處理:E_ERROR
、 E_CORE_ERROR
、 E_CORE_WARNING
、 E_COMPILE_ERROR
、 E_COMPILE_WARNING
, E_PARSE
、和在調用 set_error_handler() 函數所在文件中產生的大多數 E_STRICT
。 只能捕獲系統產生的一些Warning、Notice、Deprecated級別的錯誤。
能夠在同一個頁面使用restore_error_handler()函數取消自定義函數的接管。
register_shutdown_function(),此函數會在PHP程序終止或者die()時觸發一個函數,給PHP一個短暫的迴光返照。捕獲PHP的錯誤:Fatal Error、Parse Error等
error_get_last();這個函數能夠拿到本次執行產生的全部錯誤。error_get_last();返回數組的信息:
[type] - 錯誤類型
[message] - 錯誤消息
[file] - 發生錯誤所在的文件
[line] - 發生錯誤所在的行
set_exception_handler(),設置默認的異常處理程序,用在沒有用try/catch塊來捕獲的異常,也就是說無論你拋出的異常有沒有人捕獲,若是沒有人捕獲就會進入到該方法中,而且在回調函數調用後異常會停止。
<?php error_reporting(0); echo '<pre>'; register_shutdown_function('myShutDown'); set_error_handler('myError'); set_exception_handler('myException'); function myError($code, $msg, $file, $line) { var_dump(compact('code', 'msg', 'file', 'line')); } function myShutDown() { $data = error_get_last(); if(is_null($data)){ var_dump('nothing error'); } else { var_dump('error',$data); } } function myException($e) { var_dump('myException:'.$e->getMessage()); } // require 'a.php'; // throw new Exception("throw exception", 1); // trigger_error('throw-error', E_USER_ERROR); try{ fun(); }catch(Exception $e){ var_dump('Exception:'.$e->getMessage()); }catch(Throwable $e){
// php7
var_dump('Throable:'.$e->getMessage()); }finally{ var_dump('finally'); }
類比 thinkphp5.1 中的錯誤處理機制:
public static function register() { error_reporting(E_ALL); set_error_handler([__CLASS__, 'appError']); set_exception_handler([__CLASS__, 'appException']); register_shutdown_function([__CLASS__, 'appShutdown']); } /** * Error Handler * @access public * @param integer $errno 錯誤編號 * @param integer $errstr 詳細錯誤信息 * @param string $errfile 出錯的文件 * @param integer $errline 出錯行號 * @throws ErrorException */ public static function appError($errno, $errstr, $errfile = '', $errline = 0) { $exception = new ErrorException($errno, $errstr, $errfile, $errline); if (error_reporting() & $errno) { // 將錯誤信息託管至 think\exception\ErrorException throw $exception; } self::getExceptionHandler()->report($exception); } /** * Exception Handler * @access public * @param \Exception|\Throwable $e */ public static function appException($e) { if (!$e instanceof \Exception) { $e = new ThrowableError($e); } self::getExceptionHandler()->report($e); if (PHP_SAPI == 'cli') { self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e); } else { self::getExceptionHandler()->render($e)->send(); } } /** * Shutdown Handler * @access public */ public static function appShutdown() { if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) { // 將錯誤信息託管至think\ErrorException $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']); self::appException($exception); } // 寫入日誌 Container::get('log')->save(); }
demo:
a.php內容: <?php // 模擬Fatal error錯誤 //test(); // 模擬用戶產生ERROR錯誤 //trigger_error('zyf-error', E_USER_ERROR); // 模擬語法錯誤 var_dump(23+-+); // 模擬Notice錯誤 //echo $f; // 模擬Warning錯誤 //echo '123'; //ob_flush(); //flush(); //header("Content-type:text/html;charset=gb2312"); b.php內容: <?php error_reporting(0); register_shutdown_function('zyfshutdownfunc'); function zyfshutdownfunc() { if ($error = error_get_last()) { var_dump('<b>register_shutdown_function: Type:' . $error['type'] . ' Msg: ' . $error['message'] . ' in ' . $error['file'] . ' on line ' . $error['line'] . '</b>'); } } set_error_handler('zyferror'); function zyferror($type, $message, $file, $line) { var_dump('<b>set_error_handler: ' . $type . ':' . $message . ' in ' . $file . ' on ' . $line . ' line .</b><br />'); } require 'a.php';
通常在生產環境下推薦修改php.ini error_report(0)。
display_errors
錯誤回顯,通常經常使用語開發模式,可是不少應用在正式環境中也忘記了關閉此選項。錯誤回顯能夠暴露出很是多的敏感信息,爲攻擊者下一步攻擊提供便利。推薦關閉此選項。 一旦某個產品投入使用,那麼第一件事就是應該將display_errors選項關閉,以避免由於這些錯誤所透露的路徑、數據庫鏈接、數據表等信息而遭到黑客攻擊。
1 # vim /etc/php.inidisplay_errors = Off 2 log_errors = On 3 error_log = /var/log/php-error.log
PHP.ini中display_errors = Off失效的解決
問題: PHP設置文件php.ini中明明已經設置display_errors = Off,可是在運行過程當中,網頁上仍是會出現錯誤信息。
解決: 經 查log_errors= On,據官方的說法,當這個log_errors設置爲On,那麼必須指定error_log文件,若是沒指定或者指定的文件沒有權限寫入,那麼照樣會輸 出到正常的輸出渠道,那麼也就使得display_errors 這個指定的Off失效,錯誤信息仍是打印了出來。因而將log_errors = Off,問題就解決了。
4、PHP7對異常機制的改進
PHP7實現了一個全局的Throwable接口,原來的Exception和部分Error都實現了這個接口,以接口的方式定義了異常的繼承結構。如今大多數的錯誤會被當作Error異常拋出,但仍是不夠完善,只有部分錯誤實現了Throwable接口。
這種Error異常能夠像Exception異常被第一個匹配的try/catch塊捕獲。若是沒有匹配的catch塊,則調用異常處理函數(set_exception_handler)進行處理。若沒有註冊此函數,則按傳統的方式處理。
<?php try { test(); } catch(Throwable $e) { echo $e->getMessage() . ' zyf'; } try { test(); } catch(Error $e) { echo $e->getMessage() . ' zyf'; }