laravel请求处理流程源码分析
金蝶云社区-allen
allen
7人赞赏了该文章 372次浏览 未经作者许可,禁止转载编辑于2018年07月08日 20:22:34

请求处理的入口文件是index.php,其主要作用是提供请求处理的统一入口,生成并初始化一个应用实例(这里实质上是一个服务容器)app,获取一个http请求处理实例kernel,获取并初始化一个请求实例request,通过kernel处理request,得到相应response index.php的主要内容如下

<?php/*
引入composer的自动加载文件,引入后就可以直接使用vender目录下的第三方扩展库了
*/require __DIR__.'/../bootstrap/autoload.php';/*
获取全局应用实例app,该实例app是一个服务容器,在整个请求的生命周期中用到的服务都是在该容器中注册和获取的
*/$app = require_once __DIR__.'/../bootstrap/app.php';/*
从服务容器中获取kernel服务,该服务包括处理整个http请求的功能
*/$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);/*
处理本次请求,并获取返回的结果
处理过程包括在服务容器中进程相关的服务注册、应用中间件、路由分配等
*/$response = $kernel->handle(    /*
    获取当前请求的实例,该实例中包含了该次请求所包含的信息,包括请求方法、url、请求参数等
    */
    $request = Illuminate\Http\Request::capture()
);$response->send();$kernel->terminate($request, $response);

bootstrap/autoload.php的内容如下

<?phpdefine('LARAVEL_START', microtime(true));/*
引入composer的自动加载文件,该文件执行了项目根目录下的composer.json和vender目录下的各第三方扩展库的composer.json中定义的自动加载规则,得到结果如下:
1.对于本项目的composer.json文件中autoload下的files,直接require其定义的文件
2.对于本项目的composer.json文件中autoload下的psr-4,在需要时会自动加载以其定义的命名空间前缀开头的文件
3.对于本项目的composer.json文件中autoload下classmap,在需要时会扫描其定义的目录或文件
4.执行vender目录下的各第三方扩展库的composer.json中定义的自动加载规则,将第三方扩展库的类加入自动加载,需要时可直接使用
*/require __DIR__.'/../vendor/autoload.php';$compiledPath = __DIR__.'/cache/compiled.php';if (file_exists($compiledPath)) {    require $compiledPath;
}

bootstrap/app.php的内容如下

<?php/*
得到一个全局的应用实例$app,该实例实际上是一个服务容器,可以在其中注册和获取服务
*/$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);/*
在$app中注册一个Http\Kernel的服务,该服务用于处理http的请求
*/$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);/*
在$app中注册一个Console\Kernel的服务,该服务用于处理命令行的请求
*/$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);return $app;

bootstrap/app.php中在得到$app时进行了一些初始化的动作,初始化的内容如下

public function __construct($basePath = null){    /*
    将应用实例$app注册到服务容器中,提供全局获取应用实例的方式
    */
    $this->registerBaseBindings();    /*
    在容器中注册事件服务和路由服务
    */
    $this->registerBaseServiceProviders();    /*
    将一些核心服务的别名设置到服务容器的别名数组中
    */
    $this->registerCoreContainerAliases();    if ($basePath) {        /*
        将项目核心目录的路径注册到容器中
        */
        $this->setBasePath($basePath);
    }
}

index.php中处理请求的逻辑如下

$response = $kernel->handle(    $request = Illuminate\Http\Request::capture()
);

请求的处理都在handle中完成,handle的逻辑如下

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) {        $e = new FatalThrowableError($e);        $this->reportException($e);        $response = $this->renderException($request, $e);
    }    $this->app['events']->fire('kernel.handled', [$request, $response]);    return $response;
}

其中处理请求的核心逻辑是在sendRequestThroughRouter中完成的,该方法的内容如下

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

    Facade::clearResolvedInstance('request');    /*
    在这里会启动一些核心服务,所谓启动就是执行这些服务的bootstrap函数
    */
    $this->bootstrap();    /*
    这里会通过管线的方式来处理一个请求,获得处理结果,请求处理顺序如下:
    request->全局前置中间件->对应的路由中间件->对应的构造函数中间件->对应的controller的method->全局后置中间件->response
    */
    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());
}

该方法在$this->bootstrap()中启动的服务如下

//php会依次执行如下类中的bootstrap函数protected $bootstrappers = [    /*
    加载环境变量,包括读取.env的内容
    */
    'Illuminate\Foundation\Bootstrap\DetectEnvironment',    /*
    加载配置文件
    */
    'Illuminate\Foundation\Bootstrap\LoadConfiguration',    /*
    配置日志
    */
    'Illuminate\Foundation\Bootstrap\ConfigureLogging',    /*
    配置异常
    */
    'Illuminate\Foundation\Bootstrap\HandleExceptions',    /*
    注册facade,读取config目录中app.aliases的内容,利用PHP的class_alias函数给相应的类设置对应的别名,为laravel的facade功能做准备
    */
    'Illuminate\Foundation\Bootstrap\RegisterFacades',    /*
    注册服务,读取config目录下的app.providers中设置的服务提供者类,依次执行这些类实例的register函数来注册服务到服务容器中
    */
    'Illuminate\Foundation\Bootstrap\RegisterProviders',    /*
    启动服务,针对刚才Illuminate\Foundation\Bootstrap\RegisterProviders获取到的服务提供者类,依次执行这些类的boot函数启动相应服务
    */
    'Illuminate\Foundation\Bootstrap\BootProviders',
];


赞 7