前言
本文為《現代 PHP》一書的學習筆記。
環境
- Windows 10
- Wnmp 3.1.0
錯誤及例外
錯誤及例外是個絕佳的工具,可以幫助開發者預防那些不可測的意外。錯誤及例外常常被搞混,它們都是在某些事情出錯時出現的。雖然現今開發者大量地依賴例外而非錯誤,仍需要對於錯誤保有基本的應對方式。
前置的
@
記號放在 PHP 函式前可以避免錯誤的產生,但這是種反模式的行為,應該避免。
例外是物件導向版本的 PHP 錯誤處理系統,可以被實例化、被拋出、被接住,兼具了激進和保守的用途。
例外
例外是 Exception
類別的物件,當遇到一個不可修復的問題(例如遠端 API 沒有回應、資料庫查詢失敗或前置條件未滿足等),例外會被拋出。
使用 new
關鍵字來實例化 Exception
物件,它有兩個主要的屬性,分別是一個訊息和一個數値碼。
1 | $exception = new Exception('Danger!', 100); |
可以使用 getCode()
和 getMessage()
方法來檢查 Exception
物件。
1 | $code = $exception->getCode(); |
拋出例外
當程式碼遇到例外情況或在當前情況無法運作時拋出例外。一旦例外被拋出,接下來的 PHP 程式碼不會被執行。
可以使用 throw
關鍵字接著一個 Exception
實體來拋出例外。
1 | throw new Exception('Something went wrong!') |
PHP 提供了內建的 Exception
子類別:
Exception
ErrorException
除此之外,Standard PHP Library 還補充了數個額外的 PHP 例外。
接住例外
被拋出的例外應該被接住並且妥善地處理。沒被接住的例外會導致致命錯誤,並且終止應用程式,甚至暴露敏感訊息。
使用 try
和 catch
將可能拋出例外的程式碼包覆起來。
範例 5-38:接住被拋出的例外
1 | try { |
使用 finally
在無論有沒有接住任何例外時,都執行其中的程式碼。
範例 5-39:接住數個被拋出的例外
1 | try { |
例外處理器
永遠設立一個全域的例外處理器,例外處理器是最終的安全網。當在開發階段時,使用例外處理器顯示除錯資訊;而在產品階段時,使用人性化的訊息。
例外處利器需要接收一個 Exception
類別作為參數,可以使用 set_exception_handler()
函式來註冊。
1 | set_exception_handler(function (Exception $e) { |
如果以自製的例外處理器替換掉現存的處理器,可以在程式碼結束後使用 restore_exception_handler()
函式復原。
範例 5-40:設置全域例外處理器
1 | // 註冊例外處利器 |
錯誤
錯誤經常在 PHP 腳本根本性地無法執行時(例如語法錯誤)被觸發,PHP 開發者必須同時預測並處理 PHP 錯誤及例外。
可以使用 error_reporting()
函式或是在 php.ini
檔中使用 error_reporting()
告知 PHP 哪些錯誤要被回報,以及哪些錯誤要被忽略,兩者都接受名為 E_*
的常數。
開發者應該遵循以下四條規則:
- 永遠開啟錯誤回報。
- 在開發階段時顯示錯誤。
- 在產品階段不顯示錯誤。
- 永遠記錄錯誤。
錯誤處理器
錯誤處理器就像是例外處理器,可以妥善地處理錯誤,開發者需要適時地呼叫 die()
或 exit()
方法。
使用 set_error_handler()
方法註冊全域的錯誤處理器。
1 | set_error_handler($errno, $errstr, $errfile, $errline) { |
set_error_handler()
會接收五個參數:
$errno
,錯誤等級(對應到 PHP 的E_*
常數)。$errstr
,錯誤訊息。$errfile
,錯誤發生的檔案名稱。$errline
,錯誤發生的程式碼行數。$errcontext
,一個陣列指向錯誤發生時的符號表格,這是非必要的。
有的 PHP 錯誤可以被錯誤處理器函式轉變成 ErrorException
物件,並且將它拋出到現存的例外處理系統。
範例 5-41:設立全域錯誤處理器
1 | set_error_handler(function ($errno, $errstr, $errfile, $errline) { |
轉變 PHP 錯誤並不是非常地直覺,必須審慎地選擇檔案,符合 php.ini
檔中的 error_reporting
設定。
開發階段的錯誤及例外
Whoops 是一個現代的 PHP 元件,提供設計良好、容易閱讀的錯誤及例外診斷頁面,由 Filipe Dobreira 和 Denis Sokolov 建立和維護。
1 | composer require filp/whoops |
範例 5-42:註冊 Whoops 處理器
1 | require 'vendor/autoload.php'; |
產品階段的錯誤及例外
Monolog 是個非常棒的 PHP 元件,可以用來記錄錯誤。
1 | composer require monolog/monolog |
範例 5-43:使用 Monolog 作為開發階段記錄
1 | require 'vendor/autoload.php'; |
搭配 SwiftMailer 元件,可以在嚴重或緊急錯誤發生時發送電子郵件給管理者。
1 | composer require swiftmailer/swiftmailer |
範例 5-44:使用 Monolog 作為產品階段記錄
1 | require 'vendor/autoload.php'; |
參考資料
- Josh Lockhart(2015)。現代 PHP。台北市:碁峯資訊。