Laravel异常讲解

123 阅读1分钟

Laravel异常讲解

image

1.应用文件

bootstrap\app.php

$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);

2.内核请求处理

Illuminate\Foundation\Http\Kernel

use Illuminate\Contracts\Debug\ExceptionHandler;

public function handle($request)
{
    try {
        $request->enableHttpMethodParameterOverride();

        $response = $this->sendRequestThroughRouter($request);
    } catch (Exception $e) {
        $this->reportException($e);

        $response = $this->renderException($request, $e);
    } catch (Throwable $e) {
        $this->reportException($e = new FatalThrowableError($e));

        $response = $this->renderException($request, $e);
    }

    $this->app['events']->dispatch(
        new Events\RequestHandled($request, $response)
    );

    return $response;
}

protected function renderException($request, Exception $e)
{
    return $this->app[ExceptionHandler::class]->render($request, $e);
}

protected function sendRequestThroughRouter($request)
{
    $this->app->instance('request', $request);

    Facade::clearResolvedInstance('request');

    $this->bootstrap();

    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());
}


public function bootstrap()
{
    if (! $this->app->hasBeenBootstrapped()) {
        $this->app->bootstrapWith($this->bootstrappers());
    }
}

protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
];

3.应用容器

Illuminate\Foundation\Application

public function bootstrapWith(array $bootstrappers)
{
    $this->hasBeenBootstrapped = true;

    foreach ($bootstrappers as $bootstrapper) {
        $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);

        $this->make($bootstrapper)->bootstrap($this);

        $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
    }
}

4.启动绑定异常监听

Illuminate\Foundation\Bootstrap\HandleExceptions

use Illuminate\Contracts\Debug\ExceptionHandler;

public function bootstrap(Application $app)
{
    $this->app = $app;

    error_reporting(-1);

    set_error_handler([$this, 'handleError']);

    set_exception_handler([$this, 'handleException']);

    register_shutdown_function([$this, 'handleShutdown']);

    if (! $app->environment('testing')) {
        ini_set('display_errors', 'Off');
    }
}

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

public function handleException($e)
{
    if (! $e instanceof Exception) {
        $e = new FatalThrowableError($e);
    }

    try {
        $this->getExceptionHandler()->report($e);
    } catch (Exception $e) {
        //
    }

    if ($this->app->runningInConsole()) {
        $this->renderForConsole($e);
    } else {
        $this->renderHttpResponse($e);
    }
}

public function handleShutdown()
{
    if (! is_null($error = error_get_last()) && $this->isFatal($error['type'])) {
        $this->handleException($this->fatalExceptionFromError($error, 0));
    }
}

protected function getExceptionHandler()
{
    return $this->app->make(ExceptionHandler::class);
}

5.管道处理(中间件)

Illuminate\Pipeline\Pipeline

public function then(Closure $destination)
{
    $pipeline = array_reduce(
        array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)
    );

    return $pipeline($this->passable);
}

Illuminate\Routing\Pipeline

protected function prepareDestination(Closure $destination)
{
    return function ($passable) use ($destination) {
        try {
            return $destination($passable);
        } catch (Exception $e) {
            return $this->handleException($passable, $e);
        } catch (Throwable $e) {
            return $this->handleException($passable, new FatalThrowableError($e));
        }
    };
}

protected function carry()
{
    return function ($stack, $pipe) {
        return function ($passable) use ($stack, $pipe) {
            try {
                $slice = parent::carry();

                $callable = $slice($stack, $pipe);

                return $callable($passable);
            } catch (Exception $e) {
                return $this->handleException($passable, $e);
            } catch (Throwable $e) {
                return $this->handleException($passable, new FatalThrowableError($e));
            }
        };
    };
}

6.路由处理

Illuminate\Routing\Router

protected function runRouteWithinStack(Route $route, Request $request)
{
    $shouldSkipMiddleware = $this->container->bound('middleware.disable') &&
                            $this->container->make('middleware.disable') === true;

    $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);

    return (new Pipeline($this->container))
                    ->send($request)
                    ->through($middleware)
                    ->then(function ($request) use ($route) {
                        return $this->prepareResponse(
                            $request, $route->run()
                        );
                    });
}

7.中间件伪代码

7.1全局中间件
$middleware = [
    \App\Http\Middleware\CrossDomain::class,
    \App\Http\Middleware\RequestLog::class,
    \App\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \App\Http\Middleware\TrustProxies::class,
];

function () : CrossDomain
{
    function () : RequestLog
    {
        function () : CheckForMaintenanceMode
        {
            function () : ValidatePostSize
            {
                function () : TrimStrings
                {
                    function () : ConvertEmptyStringsToNull
                    {
                        function () : TrustProxies
                        {
                            return $this->dispatchToRouter();
                        } ()
                    } ()
                } ()
            } ()
        } ()
    } ()
} ()
7.2路由中间件
$middlewareGroups = [
    \App\Http\Middleware\EncryptCookies::class,
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \App\Http\Middleware\CheckLogin::class,
    \App\Http\Middleware\FormatOutput::class,
]

function () : EncryptCookies
{
    function () : AddQueuedCookiesToResponse
    {
        function () : StartSession
        {
            function () : SubstituteBindings
            {
                function () : CheckLogin
                {
                    function () : FormatOutput
                    {
                        return $this->prepareResponse(
                            $request, $route->run()
                        );
                    } ()
                } ()
            } ()
        } ()
    } ()
} ()
7.3前置操作or后置操作
function ()
{
    function ()
    {
        //前置操作

        $response = function () {

        } ();

        //后置操作

        return $response;
    } ()
} ()

8.最终链条

try {
    //发送请求
    
    try {
        //全局中间件
        
    } catch (Exception $e) {
        try {
            //路由中间件
            
            try {
                //执行路由
                
            } catch (Exception $e) {

            } catch (Throwable $e) {

            }
        } catch (Exception $e) {

        } catch (Throwable $e) {

        }
    } catch (Throwable $e) {

    }
} catch (Exception $e) {

} catch (Throwable $e) {

}