zoukankan      html  css  js  c++  java
  • 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方法,可以看“LaravelLumenExceptionsHandler”,该类实现了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" 为数组的键。

    另外,该方法规定只有致命的错误才会启动。

  • 相关阅读:
    09 python初学 (字符串)
    08 python 初学(字典)
    07 Python初学(元组)
    ubuntu 学习
    10 python 初学(Python 的编码解码)
    12 python 初学(深浅拷贝、集合)
    11 python初学 (文件)
    ubuntu 在 Windows 下的安装
    mysql常用命令总结
    关于Windows 7 下临时IPV6地址的问题,如何禁用它
  • 原文地址:https://www.cnblogs.com/augurG/p/10512541.html
Copyright © 2011-2022 走看看