摘要:而后才是一類的運行時錯誤。捕獲系統級錯誤首先我們要有一個容器,讓載入并初始化運行時候,開始執行。總結使用捕獲使用捕捉若沒有做相應的處理,則錯誤信息會提交至標準錯誤處理流程,根據的設定進行處理。
開發中使用的框架,大都可以做到優雅的回顯出語法級的錯誤,即 Parse Error(syntax error)E_PARSE,此錯誤作為面向用戶代碼最底層的錯誤如何進行捕獲?
下面主要講一下如何捕獲 E_PARSE & E_ERROR 錯誤,這里我刻意的把 E_PARSE 錯誤放前位的,因為 E_PARSE 是面向用戶腳本第一位的錯誤,即若有必然最先發生。而后才是 E_ERROR & E_WARNING & E_NOTICE ....一類的運行時錯誤。
PHP 錯誤級別
# 系統級用戶代碼的一些錯誤類型 可由 try ... catch ... 捕獲 E_PARSE 解析時錯誤 語法解析錯誤 少個分號 多個逗號一類的 致命錯誤 E_ERROR 運行時錯誤 比如調用了未定義的函數或方法 致命錯誤 # 可由 set_error_handler 捕獲處理 E_WARNING 運行時警告 調用了未定義的變量 E_NOTICE 運行時提醒 E_DEPRECATED 運行時已廢棄的函數或方法 # Zend Engine 相關的一些錯誤 內存錯誤一類的 應該也能通過 try ... catch ... 捕獲 略難測試 E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING # 用戶級自定義錯誤 可由 trigger_error 觸發 可由 set_error_handler 捕獲處理 E_USER_ERROR 用戶自定義錯誤 致命錯誤 未處理也會導致程序退出 E_USER_WARNING E_USER_NOTICE E_USER_DEPRECATED #編碼標準化警告(建議如何修改以向前兼容) E_STRICT 部分 捕獲的話 try ... catch ... 部分 set_error_handler E_RECOVERABLE_ERROR
先看一些問題代碼
天真的想法1、想關閉所有的錯誤報告
PHP 依然使用自身的錯誤機制報錯,原因很簡單:語法解析 -- 解釋運行 -- 結束退出。當腳本最基本的語法存在問題時,Zend Engine 自身就會退出執行,并回顯 Parse ERROR 錯誤信息。此時還未解釋執行用戶代碼,即 error_reporting(0) 還沒有在 Zend Engine 中對運行時做運行時環境的設定。
2、想使用 set_error_handler 捕捉錯誤
依然得不到理想的結果。
首先,這段代碼也是在解析階段就報錯了,Parse Error 直接退出了,還沒有真的執行 set_error_handler()。
官方原話講解:
如果錯誤發生在腳本執行之前(比如文件上傳時),將不會調用自定義的錯誤處理程序因為它尚未在那時注冊。再說,退一步講, set_error_handler 是用來自定義用戶級錯誤 E_USER_ERROR & E_USER_WARNING & E_USER_NOTICE & E_USER_DEPRECATED 和 部分運行時系統錯誤 E_WARING & E_NOTICE & E_DEPRECATED 的捕獲器,即語法解析錯誤 E_PARSE (Parse Error) 是無法用其捕獲到的。
官方原話講解:
以下級別的錯誤不能由用戶定義的函數來處理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在調用 set_error_handler() 函數所在文件中產生的大多數 E_STRICT。如果定義的 set_error_handler 的 handler 最后返回了 false,則此錯誤信息會繼續被 PHP 的標準錯誤處理程序處理:通過 error_reporting 的級別設定,該回顯的回顯(display_errors),該寫入錯誤日志的寫入錯誤日志(log_errors & error_log)
官方原話講解:
重要的是要記住 error_types 里指定的錯誤類型都會繞過 PHP 標準錯誤處理程序, 除非回調函數返回了 FALSE。注意,set_error_handler 是有自己的捕獲級別的,默認 E_ALL | E_STRICT,不過要出去上文說的那幾個級別,且不受 error_reporting() 設定的級別影響,即使你 error_reporting(0),set_error_handler 依然能捕捉到相應的錯誤。
若干問題1、為何很多框架都可以優雅的捕獲到語法或致命錯誤(E_PARSE & E_ERROR)呢?比如 laravel 標配的 whoops 2、E_PARSE & E_ERROR 到底如何才能捕捉到? 3、以上示例貌似都在說 E_PARSE & E_ERROR 這種錯誤無法捕獲,那讓用戶來自定義告警的 error_reporting() 的級別里為何還有它倆?既然有相應的級別設置,那就說明是可以被捕捉的,先簡單說明一下,E_ERROR 的捕捉其實很簡單,E_PARSE 的捕捉則需解釋和理解一下,會涉及到 PHP 解析和運行腳本的機制流程。
剖析 PHP 基本的運作機制其實非常簡單,看一遍就理解了(下文中一些運行機制用詞可能不準確,還請大佬放過,一切為了讓大家能容易理解)。
1、php 在解釋運行用戶代碼時,會以主腳本為載入點,Zend Engine 首先對其進行語法解析(Parse),這里一定要理解,Zend Engine 此時是對腳本的語法進行解析,腳本中的任何 ini 設置都對其無效(還沒解釋載入執行初始化),所以你設置的什么 error_reporting, display_errors, set_error_handler。只有當語法解析無誤,Zend Engine 開始載入并解釋腳本,腳本里的一些參數設置項才會開始生效。
2、php 沒有 //鏈接依賴庫 -- 編譯 -- 運行// 一說。當 php 在主腳本中 “引入依賴” 時,Zend Engine 并不會在對主腳本做語法解析時將其 “依賴” 也載入解析。Zend Engine 只會對當前的主腳本做語法解析,在解析通過后,便開始解釋執行用戶代碼,即便 “依賴” 中有 Parse Error,那也得等到真的執行到載入命令時才會加載解析-解釋-運行。
所以,我們首先要構建一個 Parse OK 的容器,初始化 Zend Engine 的一些運行時配置,比如關閉錯誤報告,這樣整個運行時就是關閉了錯誤報告的上下文,即便后續有 E_PAESE & E_ERROR 也不會回顯錯誤信息了。但我們的目的是要捕捉。
使用 try ... catch 捕獲 E_PARSE & E_ERROR解析過程:
1:error_reporting(E_ALL); 語法無誤 繼續 2:echo "this is main script" . PHP_EOL; 語法無誤 繼續 3:require_once __DIR__ . "/lib.php"; 此語法無誤 繼續 (注意:此時并不會去載入并對 lib.php 做語法解析檢查) 4:echo "hello world!" . PHP_EOL; 語法無誤繼續解析完成,語法通過,開始解釋執行
執行過程:
1:error_reporting(E_ALL); 將執行環境的錯誤告警設為用戶定義的級別,運行時用戶上下文已開始形成 2:echo "this is main script" . PHP_EOL; 輸出個字符串 3:require_once __DIR__ . "/lib.php"; 加載未曾載入過的腳本?開始加載執行 解析 - 解釋 的流程 4:echo "hello world!" . PHP_EOL; 要在 lib.php 被 解析 - 解釋 完成后才會回到此處繼續執行是不是發現了?在 lib.php 被載入前,main script 的一些運行時的參數設置已經生效,比如這里的 error_reporting(E_ALL),lib.php 解析/解釋運行時已經是在我們自定義好錯誤告警級別的上下文中了,Zend Engine 會根據我們設定的錯誤告警級別對 lib.php 進行載入。這時就可以明白 E_PARSE & E_ERROR 錯誤可被用戶設定的含義了吧。
即:你首先要有一個絕對正確的容器,負責將一些必要的用戶設定傳遞給 Zend Engine 初始化好運行時上下文,此后再載入執行的用戶代碼都將在此上下文中執行,其后的業務邏輯。
合理的代碼組織結構示例:
1、關閉所有的錯誤報告main.js
lib.js
那么 lib.php 的任何錯誤都不會被報告出來,因為 main 運行到載入 lib 時,其已向 Zend Engine 發送了 error_reporting(0); 的指令,所以 lib 中的 Parse Error 不會被報告出來。但這并不是我們想要的,我們要捕獲才對。
2、捕獲系統級錯誤 E_PARSE & E_ERROR
首先我們要有一個容器,讓 Zend Engine 載入并初始化運行時候,開始執行。
然后我們可以使用 try ... catch 捕捉錯誤,如下:輸出結果:
ParseError::__set_state(array( "message" => "syntax error, unexpected end of file, expecting "," or ";"", "string" => "", "code" => 0, "file" => "...lib.php", "line" => 2, "trace" => array (), "previous" => NULL, ))這樣便優雅的拿到了 Parse Error 錯誤,包裝一下輸出給用戶即可。
Parse Error 可以說是用戶級的最高一級錯誤了,Parse Error 了用戶腳本就退出了。
而后我們才會可能遇到 E_ERROR & E_WARNING & E_NOTICE & E_DEPRECATED 等,如下:
運行結果
Error::__set_state(array( "message" => "Call to undefined function func_not_exists()", "string" => "", "code" => 0, "file" => "...main.php", "line" => 47, "trace" => array(), "previous" => null, ))如上,語法沒有問題,所以不會有 Parse Error,Zend Engine 開始載入腳本解釋執行,因為調用了不存在的方法,E_ERROR 觸發后被我們捕獲。
完善的錯誤采集try ... catch 可以捕捉 E_PARSE & E_ERROR
set_error_handler 可以捕捉 E_WARNING & E_NOTICE & E_DEPRECATED & E_USER_*
二者聯合起來即可捕捉大部分的用戶代碼層面的錯誤
注意 set_error_handler 和 try ... catch 對錯誤捕獲后程序會繼續執行下去,并不會立即退出。
總結E_ERROR & E_PARSE 使用 try ... catch 捕獲
E_WARNING & E_NOTICE & E_DEPRECATED & E_USER_* 使用 set_error_handler 捕捉
若沒有做相應的處理,則錯誤信息會提交至 PHP 標準錯誤處理流程,根據 error_reporting / display_errors / log_errors / error_log 的設定進行處理。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/30807.html
摘要:有自身的錯誤捕獲級別,默認,且不受設定的級別的影響。捕獲錯誤異常捕獲異常捕獲類型錯誤返回值參數類型不正確嚴格模式下更容易出現捕獲解析錯誤語法錯誤除無法捕獲但除取余可以捕獲很無奈基本錯誤這里要注意的是,在中依然無法隱式的完美捕獲。 PHP(PHP_VERSION >= 7) 的 Error / Exception 的捕獲與處理還是值得一說的,優雅處理錯誤與異常,在提升框架友好度的同時,也...
摘要:至,有同樣的行為。表示關閉所有錯誤報告表示顯示二函數說明設置應該報告何種錯誤說明函數能夠在運行時設置指令。后果是導致腳本終止不再繼續運行。初始化啟動過程中發生的警告非致命錯誤。用戶產少的警告信息。出外的所有錯誤和警告信息。 錯誤報告級別:指定了在什么情況下,腳本代碼中的錯誤(這里的錯誤是廣義的錯誤,包括E_NOTICE注意、E_WARNING警告、E_ERROR致命錯誤等)會以錯誤報告...
摘要:運行時警告非致命錯誤。初始化啟動過程中發生的警告非致命錯誤。表示腳本遇到可能會表現為錯誤的情況用戶產生的通知信息。該函數以數組的形式返回最后發生的錯誤。所以異常經常被當做程序的控制流程使用。在調用后異常會中止。 Error Error級別 Fatal Error:致命錯誤(腳本終止運行) E_ERROR 致命的運行時的致命錯誤,終止程序執行 E_CORE_ERROR ...
摘要:中的參數就是出錯時顯示中詳解說明設定錯誤訊息回報的等級。例如用有問題的常規表示法呼叫。通常會顯示出來,亦會中斷程式執行。意即用這個遮罩無法追查到記憶體配置或其它的錯誤。從語法中剖析錯誤。類似,但不包括核心錯誤警告。 value constant 1 E_ERROR 2 E_WARNING 4 E_PARSE 8 E_NOTICE 16 E_CORE_ERROR ...
摘要:背景框架核心代碼自動實現了異常,并實現了拋出的對應頁面和方法,對于一些個性化需求特別是接口類型的應用,會不合適。因此需要在不改版核心代碼目錄下文件,來改變對異常及等相關異常的處理。方法說明框架比有比較大的改動,其中之一就是對異常的處理。 背景 ci3.0框架核心代碼自動實現了異常,并實現了拋出的對應頁面和方法,對于一些個性化需求特別是接口類型的應用,會不合適。因此需要在不改版核心代碼 ...
閱讀 1428·2021-11-15 11:38
閱讀 3577·2021-11-09 09:47
閱讀 1976·2021-09-27 13:36
閱讀 3223·2021-09-22 15:17
閱讀 2560·2021-09-13 10:27
閱讀 2871·2019-08-30 15:44
閱讀 1180·2019-08-27 10:53
閱讀 2712·2019-08-26 14:00