Laravel Exception處理邏輯解析


Laravel Exception處理邏輯解析

vendor/laravel/framework/src/Illuminate/Foundation/Application.php

  1. app首先繼承了container,作為一個容器類存在
  2. 注冊了laravel運行過程的需要的基礎類進容器,並且生成了運行需要的實例。承擔了初始化功能。這里需要額外說一下,app里面說的所謂注冊,不是指綁定,應該是直接直接實例化了,並注入到容器。但是,針對provider,實例化了provider,並運行了,並不會生成實際的類,而是將類綁定。

ExceptionHandler的注冊就是在Application的__construct方法中。

$this->registerErrorHandling();

接着我們來到定義該方法的trait:RegistersExceptionHandlers找到該方法。看一下該方法實現了什么樣的邏輯。便於理解我加上了一些注釋。

protected function registerErrorHandling()
    {
        error_reporting(-1);//-1報告所有異常,包括后續新定義的異常級別,作用與E_ALL相同
        
/** set_error_handler,set_exception_handler,register_shutdown_function分別注冊不同級別不同類型異常的處理方法。 */

        set_error_handler(function ($level, $message, $file = '', $line = 0) {
            if (error_reporting() & $level) {
                throw new ErrorException($message, 0, $level, $file, $line);
            }
        });//代替標准錯誤處理方法

        set_exception_handler(function ($e) {
            $this->handleUncaughtException($e);
        });//兜底異常處理方法注冊

        register_shutdown_function(function () {
            $this->handleShutdown();
        });//注冊一個在腳本正常或非正常情況終止執行時調用的方法。(終極兜底)
    }

我們看到laravel主要通過三個原生方法來實現主要的ExceptionHandler機制。下面我們分開看一下這里都分別注冊了哪些函數。

set_error_handler

function ($level, $message, $file = '', $line = 0) {
            if (error_reporting() & $level) {
                throw new ErrorException($message, 0, $level, $file, $line);
            }
        }

這塊很簡單,set_error_handler注冊的函數會代替原生的報錯處理邏輯。這里可以看到laravel將執行error作為異常拋出。並且保留了error的主要信息。(level,msg,file,line)

set_exception_handler

/**set_exception_handler(function ($e) {
            $this->handleUncaughtException($e);
});**/
        
protected function handleUncaughtException($e)
    {
    //從容器中實例化一個真正的handler。(使用make方法)
        $handler = $this->resolveExceptionHandler();
    //如果獲取到的是Error,通過Error信息實例化一個已定義的“可拋出的致命錯誤”
        if ($e instanceof Error) {
            $e = new FatalThrowableError($e);
        }
    //記錄日志(先判斷是否報告)
        $handler->report($e);
    //render錯誤
        if ($this->runningInConsole()) {
            $handler->renderForConsole(new ConsoleOutput, $e);
        } else {
            $handler->render($this->make('request'), $e)->send();
        }
    }   
  1. resolveExceptionHandler方法從容器中make了一個handler實例,從該方法可以找到laravel實現的handler方法。該方法會判斷是否綁定抽象類型來判斷使用開發者自行綁定的ExceptionHandler還是系統自帶的。handler的作用只有一點,就是解析異常,並將異常處理成我們想要的,更加用戶友好的方式展示。(++render方法,可以看“Laravel\Lumen\Exceptions\Handler”,該類實現了Laravel的ExceptionHandler接口,想要自定義異常輸出的話也可以參考該類++)
  2. report和render方法都是handler中定義的,report會先進行判斷,並根據判斷結果決定是否記錄log。render自然不必多說,formatexception info,並作為一個HTTP response輸出。

register_shutdown_function

protected function handleShutdown()
    {
        if (! is_null($error = error_get_last()) && $this->isFatalError($error['type'])) {
            $this->handleUncaughtException(new FatalErrorException(
                $error['message'], $error['type'], 0, $error['file'], $error['line']
            ));
        }
    }

error_get_last()是5.2版本實現的方法,能夠很好的配合的register_shutdown_function進行兜底處理。改善了需要自定義變量判斷的方法。

error_get_last 返回了一個關聯數組,描述了最后錯誤的信息,以該錯誤的 "type"、 "message"、"file" 和 "line" 為數組的鍵。

另外,該方法規定只有致命的錯誤才會啟動。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM