天天看點

攔截PHP各種異常和錯誤,發生緻命錯誤時進行報警,萬事防患于未然

在日常開發中,大多數人的做法是在開發環境時開啟調試模式,在産品環境關閉調試模式。在開發的時候可以檢視各種錯誤、異常,但是線上上就把錯誤顯示的關閉。

上面的情形看似很科學,有人解釋為這樣很安全,别人看不到錯誤,以免洩露重要資訊...

但是你有沒有遇到這種情況,線下好好的,一上線卻運作不起來也找不到原因...

一個腳本,跑了好長一段時間,一直沒有問題,有一天突然中斷了,然後了也沒有任何記錄都不造啥原因...

線上一個付款,别人明明付了款,但是我們卻沒有記錄到,自己親自去實驗,卻是好的...

種種以上,都是因為大家關閉了錯誤資訊,并且未将錯誤、異常記錄到日志,導緻那些随機發生的錯誤很難追蹤。這樣沖突就來了,即不要顯示錯誤,又要追蹤錯誤,這如何實作了?

以上問題都可以通過PHP的錯誤、異常機制及其内建函數'set_exception_handler','set_error_handler','register_shutdown_function' 來實作

'set_exception_handler' 函數 用于攔截各種未捕獲的異常,然後将這些交給使用者自定義的方式進行處理

'set_error_handler' 函數可以攔截各種錯誤,然後交給使用者自定義的方式進行處理

'register_shutdown_function' 函數是在PHP腳本結束時調用的函數,配合'error_get_last'可以擷取最後的緻命性錯誤

這個思路大體就是把錯誤、異常、緻命性錯誤攔截下來,交給我們自定義的方法進行處理,我們辨識這些錯誤、異常是否緻命,如果是則記錄的資料庫或者檔案系統,然後使用腳本不停的掃描這些日志,發現嚴重錯誤立即發送郵件或發送短信進行報警

首先我們定義錯誤攔截類,該類用于将錯誤、異常攔截下來,用我們自己定義的處理方式進行處理,該類放在檔案名為'errorHandler.class.php'中,代碼如下

上述代碼中,有個'errorHandlerException'類,該類放在檔案'errorHandlerException.class.php'中,該類用于将錯誤轉換為異常,以便記錄錯誤發生的檔案、行号、錯誤代碼、錯誤資訊等資訊,同時其方法'isFatalError'用于辨識該錯誤是否是緻命性錯誤。這裡我們為了友善管理,将錯誤進行編号并命名。該類的代碼如下

在錯誤攔截類中,需要使用者自己定義實作錯誤記錄的方法('logException'),這個地方需要注意,有些錯誤可能在一段時間内不斷發生,是以隻需記錄一次即可,你可以使用錯誤代碼、檔案、行号、錯誤詳情 生成一個MD5值用于記錄該錯誤是否已經被記錄,如果在規定時間内(一個小時)已經被記錄過則不需要再進行記錄

然後我們定義一個檔案,用于執行個體化以上類,捕獲各種錯誤、異常,該檔案命名為'registerErrorHandler.php', 内如如下

剩下的就是需要你在你的入口檔案引入該檔案,定義調試模式,然後實作你自己記錄錯誤的方法即可

需要注意的是,有些錯誤在你進行注冊之前已經發生并且導緻腳本中斷是無法記錄下來的,因為此時'registerErrorHandler::register()' 尚未執行已經中斷了

還有就是'set_error_handler'這個函數不能捕獲下面類型的錯誤 <code>E_ERROR</code>、 <code>E_PARSE</code>、 <code>E_CORE_ERROR</code>、 <code>E_CORE_WARNING</code>、<code>E_COMPILE_ERROR</code>、 <code>E_COMPILE_WARNING, 這個可以在官方文檔中看到,但是本處無妨,因為以上錯誤是解析、編譯錯誤,這些都沒有通過,你是不可能釋出上線的</code>

以上代碼經過嚴格測試,并且已經應用線上上環境,大家可以根據自己需要進行更改使用