1. 程式人生 > 實用技巧 >PHP7中異常與錯誤處理和自定義異常

PHP7中異常與錯誤處理和自定義異常

7.2版本異常與錯誤的概述

什麼叫做異常?

異常是指程式執行中不符合預期情況以及與正常流程不同的狀況。

比如你連結資料庫,在引數都寫上去的條件下,發現連結不上去,這就屬於不符合預期

可以被 try-catch 捕捉得到

什麼叫做錯誤?

是屬於php程式自身的問題,一般是由非法的語法,環境問題導致的,使得編譯器無法通過檢查,甚至無法執行的情況。
平時遇到的 warming、notice都是錯誤,只是級別不同而已。

例如:

  • TypeError(型別錯誤) 我規定的函式引數型別和傳入的引數不一致
  • ArithmeticError (算數錯誤)
  • ParseError (解析錯誤)在調入的檔案中,include "demo.php",或者 eval();中有語法錯誤造成解析失敗
  • AssertionError(斷言錯誤)當assert生效時產生該錯誤
  • DivisionByZeroError (分母為零) 運算過程中例如除法,分母為0

除了這幾種情況,其餘全部為異常

異常處理

在以前的 php5.X 中 並且不能被 try-catch 捕捉得到,到了 php 7.x 中,定義了一個 Throwable 介面 並使得大部分的 Error 和
Exception 實現了該介面,我們得以在 try-catch 中丟擲該錯誤

所以說以後想要捕獲異常,而你又不知道此異常是 Error 還是 Exception 的話,可以向這樣丟擲

try{
    ……
}catch(Throwable $e){
    ……
}

錯誤的級別

在 php 中的錯誤也是有級別的

Parse error>Fatal Error>Waning>Notice>Deprecated

Deprecated 最低級別的錯誤(不推薦,不建議)
使用一些過期函式的時候會出現,程式繼續執行

Notice 通知級別的錯誤
使用一些未定義變數、常量或者陣列key沒有加引號的時候會出現,程式繼續執行
        E_NOTICE      // 執行時通知。表示指令碼遇到可能會表現為錯誤的情況.
        E_USER_NOTICE // 使用者產生的通知資訊。
        
Waning 警告級別的錯誤
程式出問題了,需要修改程式碼!!!程式繼續執行
        E_WARNING         // 執行時警告 (非致命錯誤)。
        E_CORE_WARNING    // PHP初始化啟動過程中發生的警告 (非致命錯誤) 。
        E_COMPILE_WARNING // 編譯警告
        E_USER_WARNING    // 使用者產生的警告資訊
        
Fatal Error 錯誤級別的錯誤
程式直接報錯,需要修改程式碼!!!中斷程式執行,可使用register_shutdown_function()函式在程式終止前觸發一個函式
        E_ERROR         // 致命的執行錯誤,錯誤無法恢復,暫停執行指令碼
        E_CORE_ERROR    // PHP啟動時初始化過程中的致命錯誤
        E_COMPILE_ERROR // 編譯時致命性錯,就像由Zend指令碼引擎生成了一個E_ERROR
        E_USER_ERROR    // 自定義錯誤訊息。像用PHP函式trigger_error(錯誤型別設定為:E_USER_ERROR)
        
Parse error 語法解析錯誤
語法檢查階段報錯,需要修改程式碼!!!中斷程式執行,除了修改ini檔案,將錯誤資訊寫到日誌中,什麼也做不了
        E_PARSE  //編譯時的語法解析錯誤

自定義錯誤處理程式

有的時候,php 中自帶的錯誤處理程式,並不能完全滿足我們得需要,大部分時候,我們都需要手動重寫異常處理。

php 給我們提供了三個函式來幫助我們來處理,分別是

set_error_handler()

  • 函式來託管錯誤處理程式,可自行定製錯誤的處理流程。
  • 如果此函式之前的程式碼發生錯誤,那麼不會呼叫我們自定義的處理函式,因為還未註冊
  • 設定此函式後 error_reporting() 將會失效
  • 以下級別的錯誤不能由使用者定義的函式來處理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING 該函式只能捕捉我們的 部分 Warning 和 Note 級別的錯誤

set_exception_handler()

  • 用於沒有被捕獲的異常處理

register_shutdown_function()

  • 作用:註冊一個會在php中止時執行的函式
  • 捕獲PHP的錯誤:Fatal Error、Parse Error等,這個方法是PHP指令碼執行結束前最後一個呼叫的函式,比如指令碼錯誤、die()、exit、異常、正常結束都會呼叫,
  • 如果拿來用錯誤處理的時候,需要配合error_get_last()它能獲取最後發生的錯誤。
// 舉例:
register_shutdown_function('shutdown');

function shutdown()
{
    if ($error = error_get_last()) {
        var_dump($error);
    }
}
$name   //沒寫 ; 號

執行結果
Parse error: syntax error, unexpected ';' in /app/swoole/errorDemo.php on line 34
Emmmmm 這不扯淡嗎? 分明分明沒有執行呢?

其實原因使因為,程式執行前,我們 php 會先檢查我們程式的語法問題,如果沒有問題,我們才能執行我們的程式。

我們上面的程式碼沒用通過我們的語法檢查,所以直接報錯。

那麼問題來了? 我們在框架中的時候,為什麼是框架都是框架給我們報錯呢?

框架的錯誤處理

在框架中,其程式碼是通過一個入口檔案來載入的。而我們php檢測語法錯誤的時候,只檢查我們的 index.php 有沒有錯誤, require 檔案中的程式碼是不會受到檢測的。在Index.php檔案中通常會定義一些錯誤異常的處理。當我們程式碼出錯時,那是在 run-time 中檢測的錯誤,我們的框架可以根據我們編寫的錯誤異常自行做出處理。

下面我們舉個例子 在 ThinkPHP5中的異常處理

// [ 應用入口檔案 ]  index.php
namespace think;

// 載入基礎檔案
require __DIR__ . '/../thinkphp/base.php';

// 支援事先使用靜態方法設定Request物件和Config物件

// 執行應用並響應
Container::get('app')->run()->send();

在我們的入口檔案中,載入了base.php在這個檔案中,TP 定義了自己的異常處理

// 載入Loader類
require __DIR__ . '/library/think/Loader.php';

// 註冊自動載入
Loader::register();

// 註冊錯誤和異常處理機制
Error::register();

// 實現日誌介面
if (interface_exists('Psr\Log\LoggerInterface')) {
   //doSomething
}

// 註冊類庫別名
Loader::addClassAlias([
   //doSomething
]);
/**
     * 註冊異常處理
     * @access public
     * @return void
     */
    public static function register()
    {
        error_reporting(E_ALL);
        set_error_handler([__CLASS__, 'appError']);
        set_exception_handler([__CLASS__, 'appException']);
        register_shutdown_function([__CLASS__, 'appShutdown']);
    }

可以看到 TP是在入口指令碼就註冊了 異常處理機制,分別把 Error 、Exception、Shutdown的處理都註冊進來。後序所有的異常都不會走PHP原本的異常而是走 TP 自定義的異常。

對PHP後端技術,對PHP架構技術感興趣的朋友,我的官方群點選此處,一起學習,相互討論。

PHP進階學習思維導圖、面試;文件、視訊資源免費獲取

群內已經有管理將知識體系整理好(原始碼,學習視訊等資料),歡迎加群免費領取。

部分資料截圖: