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