Laravel启动Kernel后,项目怎样了 ?

419 阅读2分钟

Kernel实例调用handle方法,意味着laravel的核心和公用代码已经准备完毕,此项目正式开始运行

代码:/app/Http/Kernel.php

<?php namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel {

    //这是在调用路由之前需要启动的中间件,一般都是核心文件,不要修改
    protected $middleware = [
        'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
        'Illuminate\Cookie\Middleware\EncryptCookies',
        'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
        'Illuminate\Session\Middleware\StartSession',
        'Illuminate\View\Middleware\ShareErrorsFromSession',
        'App\Http\Middleware\VerifyCsrfToken',
    ];

    //这是我们在router.php文件里面或者Controller文件里面,可以使用的Middleware元素,可以自定义加入很多
    protected $routeMiddleware = [
        'auth' => 'App\Http\Middleware\Authenticate',
        'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
        'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
        'test' => 'App\Http\Middleware\testMiddleWare',
    ];

}

大家看到了,其实这个文件里面没有handle方法,只有一些属性定义,所以真正的handle方法,实在父类里面实现的

代码:…/Illuminate/Foundation/Http/Kernel.php

//好多代码,见几个我看过的扯扯,其他的期待你们补上

//这个很重要,是项目的一些启动引导项,Kernel的重要步骤中,首先就是启动这些文件的bootstrap方法
protected $bootstrappers = [
    //检测环境变量文件是否正常
    'Illuminate\Foundation\Bootstrap\DetectEnvironment',
    //取得配置文件,即把/config/下的所有配置文件读取到容器(app()->make('config')可以查看所有配置信息)
    'Illuminate\Foundation\Bootstrap\LoadConfiguration',
    //绑定一个名字为log的实例到容器,怎么访问??(app()->make('log'))
    'Illuminate\Foundation\Bootstrap\ConfigureLogging',
    //设置异常抓取信息,这个还没仔细看,但大概就是这个意思
    'Illuminate\Foundation\Bootstrap\HandleExceptions',
    //把/config/app.php里面的aliases项利用PHP库函数class_alias创建别名,从此,我们可以使用App::make('app')方式取得实例
    'Illuminate\Foundation\Bootstrap\RegisterFacades',
    //把/config/app.php里面的providers项,注册到容器
    'Illuminate\Foundation\Bootstrap\RegisterProviders',
    //运行容器中注册的所有的ServiceProvider中得boot方法
    'Illuminate\Foundation\Bootstrap\BootProviders',
];

//真正的handle方法
public function handle($request)
{
    try
    {
        //主要是这行,调度了需要运行的方法
        return $this->sendRequestThroughRouter($request);
    }
    catch (Exception $e)
    {
        $this->reportException($e);

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


protected function sendRequestThroughRouter($request)
{
    $this->app->instance('request', $request);
    Facade::clearResolvedInstance('request');
    //运行上述$bootstrappers里面包含的文件的bootstrap方法,运行的作用,上面已经注释
    $this->bootstrap();
    //这是在对URL进行调度之前,也就是运行Route之前,进行的一些准备工作
    return (new Pipeline($this->app))    //不解释
                ->send($request)        //继续不解释
                //需要运行$this->middleware里包含的中间件
                ->through($this->middleware)
                //运行完上述中间件之后,调度dispatchToRouter方法,进行Route的操作
                ->then($this->dispatchToRouter());
}

//前奏执行完毕之后,进行Route操作
protected function dispatchToRouter()
{
    return function($request)
    {
        $this->app->instance('request', $request);
        //跳转到Router类的dispatch方法
        return $this->router->dispatch($request);
    };
}

下面就需要根据URL和/app/Http/routes.php文件,进行Route操作

文件:…/Illuminate/Routing/Router.php

//代码好多,挑几个解释

public function dispatch(Request $request)
{
    $this->currentRequest = $request;
    //在4.2版本里面,Route有一个筛选属性;5.0之后的版本,被Middleware代替
    $response = $this->callFilter('before', $request);

    if (is_null($response))
    {    
        //继续调度
        $response = $this->dispatchToRoute($request);
    }

    $response = $this->prepareResponse($request, $response);
    //在4.2版本里面,Route有一个筛选属性;5.0之后的版本,被Middleware代替
    $this->callFilter('after', $request, $response);

    return $response;
}

public function dispatchToRoute(Request $request)
{
    $route = $this->findRoute($request);
    $request->setRouteResolver(function() use ($route)
    {
        return $route;
    });

    $this->events->fire('router.matched', [$route, $request]);
    $response = $this->callRouteBefore($route, $request);

    if (is_null($response))
    {
        // 只看这一行,还是调度文件
        $response = $this->runRouteWithinStack(
            $route, $request
        );
    }

    $response = $this->prepareResponse($request, $response);
    $this->callRouteAfter($route, $request, $response);

    return $response;
}

//干货来了
protected function runRouteWithinStack(Route $route, Request $request)
{
    // 取得routes.php里面的Middleware节点
    $middleware = $this->gatherRouteMiddlewares($route);
    //这个有点眼熟
    return (new Pipeline($this->container))
                    ->send($request)
                    //执行上述的中间件
                    ->through($middleware)
                    ->then(function($request) use ($route)
                    {    
                        //不容易啊,终于到Controller类了
                        return $this->prepareResponse(
                            $request,
                            //run控制器
                            $route->run($request)
                        );
                    });
}

public function run(Request $request)
{
    $this->container = $this->container ?: new Container;
    try
    {
        if ( ! is_string($this->action['uses']))
            return $this->runCallable($request);
        if ($this->customDispatcherIsBound())
        //实际上是运行了这行
            return $this->runWithCustomDispatcher($request);

        //其实我是直接想运行这行
        return $this->runController($request);
    }
    catch (HttpResponseException $e)
    {
        return $e->getResponse();
    }
}

//继续调度,最终调度到.../Illuminate/Routing/ControllerDispatcher.php文件的dispatch方法
protected function runWithCustomDispatcher(Request $request)
{
    list($class, $method) = explode('@', $this->action['uses']);

    $dispatcher = $this->container->make('illuminate.route.dispatcher');
    return $dispatcher->dispatch($this, $request, $class, $method);
}

文件:…/Illuminate/Routing/ControllerDispatcher.php

public function dispatch(Route $route, Request $request, $controller, $method)
{
    $instance = $this->makeController($controller);

    $this->assignAfter($instance, $route, $request, $method);

    $response = $this->before($instance, $route, $request, $method);

    if (is_null($response))
    {
        //还要调度
        $response = $this->callWithinStack(
            $instance, $route, $request, $method
        );
    }

    return $response;
}

protected function callWithinStack($instance, $route, $request, $method)
{
    //又是Middleware......有没有忘记,官方文档里面Middleware可以加在控制器的构造函数中!!没错,这个Middleware就是在控制器里面申明的
    $middleware = $this->getMiddleware($instance, $method);
    //又是这个,眼熟吧
    return (new Pipeline($this->container))
                ->send($request)
                //再次运行Middleware
                ->through($middleware)
                ->then(function($request) use ($instance, $route, $method)
                {    
                    运行控制器,返回结果
                    return $this->call($instance, $route, $method);
                });
}

这就是从入口文件到控制器中间,进行的一系列操作