laravel源码详解

来源:互联网 发布:先导爱知在第六季出现 编辑:程序博客网 时间:2024/05/31 06:22

安装,和创建项目,都是通过Composer,简单,略过。

Entry && Kernel

网站入口文件,${Laravel-project}/public/index.PHP:

$app = require_once __DIR__.'/../bootstrap/app.php';$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);$response = $kernel->handle(    $request = Illuminate\Http\Request::capture());$response->send();$kernel->terminate($request, $response);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

生成Request,处理Request(Http\Kernel::handle()),生成Response,发送Resonse。常规的Web处理流程。

注意 Illuminate\Contracts\Http\Kernel 只是一个Interface:

interface Kernel{    public function bootstrap();    public function handle($request);    public function terminate($request, $response);    public function getApplication();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可见入口文件中的代码,$kernel = $app->make是关键,后面都是调用Kerenl接口的实例对象方法(特别是Kernel::handle())。

可是 $app 是谁创建的呢?是什么类型呢?

Bootstrap && Application

入口文件的第一行代码:

$app = require_once __DIR__.'/../bootstrap/app.php';
  • 1
  • 1

引导我们去查看 bootstrap/app.php 源码,代码不多,都拿过来看看吧:

$app = new Illuminate\Foundation\Application(    realpath(__DIR__.'/../'));$app->singleton(    Illuminate\Contracts\Http\Kernel::class,    App\Http\Kernel::class);$app->singleton(    Illuminate\Contracts\Console\Kernel::class,    App\Console\Kernel::class);$app->singleton(    Illuminate\Contracts\Debug\ExceptionHandler::class,    App\Exceptions\Handler::class);return $app;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

第一行创建,最后一行返回。现在我们知道啦,$appIlluminate\Foundation\Application类型的对象。(因为require_once$app是一个单实例对象。中间几行代码后面可能有用,此处暂时忽略。)

自然,$kernel = $app->make()也就是调用Applicaton::make()了,代码拿来看一下:

/** * Resolve the given type from the container. * (Overriding Container::make) * @return mixed */public function make($abstract, array $parameters = []){    $abstract = $this->getAlias($abstract);    if (isset($this->deferredServices[$abstract])) {        $this->loadDeferredProvider($abstract);    }    return parent::make($abstract, $parameters);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

然而还是不清楚它具体返回哪个类型。

对照前面bootstrap的代码:

$app->singleton(    Illuminate\Contracts\Http\Kernel::class,    App\Http\Kernel::class);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

我们推论得出:$kernel = $app->make()的真实类型是App\Http\Kernel(同时实现了接口Illuminate\Contracts\Http\Kernel)。 
这个推论很容易被证实,此处省略细节($app->singleton->bind->alias->make())。 
更加具体的创建Kernel对象的细节十分琐碎,我们也一并忽略,有兴趣的可以去看父类方法Illuminate\Container\Container::make()/build()的代码。

现在我们初步总结一下:先new出Application类型对象appapp创建Kernel类型对象kernelkernel处理Request、生成Response并发送给客户端。

附加:$app是被直接new出来的(new Illuminate\Foundation\Application),其构造函数做了一些重要的初始化工作,整理代码如下:

public function __construct($basePath = null){    $this->instance('app', $this);    $this->instance('Illuminate\Container\Container', $this);    $this->register(new EventServiceProvider($this));    $this->register(new RoutingServiceProvider($this));    // ...    $this->setBasePath($basePath);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Kernel::handle() && Request=>Response

下一步我想知道 $response = $kernel->handle($request) 内部具体做了什么工作,是怎么处理Request并生成Response的。

前面我们已经分析过了,$kernel的真实类型是App\Http\Kernel,也实现了接口Illuminate\Contracts\Http\Kernel

拿来App\Http\Kernel::handle()的源代码看看,咦,没有此方法。 
看其父类同名方法Illuminate\Foundation\Http\Kernel::handle()代码:

public function handle($request){    try {        $request->enableHttpMethodParameterOverride();        $response = $this->sendRequestThroughRouter($request);    } catch (...) {        // ...    }    $this->app['events']->fire('kernel.handled', [$request, $response]);    return $response;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

上面代码中我感兴趣的只有sendRequestThroughRouter($request)这个调用,进去看一下:

/** * Send the given request through the middleware / router. * * @param  \Illuminate\Http\Request  $request * @return \Illuminate\Http\Response */protected function sendRequestThroughRouter($request){    $this->app->instance('request', $request);    Facade::clearResolvedInstance('request');    $this->bootstrap(); //! Note: $kernel->bootstrap();    return (new Pipeline($this->app))                ->send($request)                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)                ->then($this->dispatchToRouter());}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

上面代码中最后一行是我们关注的重点,它把Request送进一个新创建的流水线(Pipeline), 
供各个中间件(Middleware)处理,然后再派发给路由器(Router)。下文将展开分析。

Pipeline && Middleware && Router

流水线,中间件,路由器。

Pipleline

流水线Illuminate\Pipeline\Pipeline实现了接口Illuminate\Contracts\Pipeline\Pipeline。 
其主要接口方法有send,through,via,then。其中send设置Request对象,through设置中间件数组,via设置方法名(默认为”handle”),then最终运行此并执行闭包参数(then的代码极其复杂,各种闭包嵌套,把我搞糊涂了,有兴趣的朋友可以看一下)。

简单推断来说,其工作内容是:依次调用各中间件的handle方法。特别的,如果某个中间件是闭包,以闭包的形式调用之。

Middleware

中间件Illuminate\Contracts\Routing\Middleware是一个很简单的接口:

interface Middleware{    /**     * Handle an incoming request.     *     * @param  \Illuminate\Http\Request  $request     * @param  \Closure  $next     * @return mixed     */    public function handle($request, Closure $next);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

其文档也极其简陋,看不出太多有价值的信息。第二个参数什么意思,返回值什么意思,鬼才能看出来。可能需要从其他地方入手研究中间件。

Router

将请求派发给Router的调用流程:$kernel->handle($request) => $kernel->sendRequestThroughRouter => $kernel->dispatchToRouter() => $kernel->router->dispatch($request)

其中$kernel->router是创建$kernel时通过构造函数传入的Router对象。

有必要先看一下Router是怎样创建出来的。调用流程:$app = new Applicaton(__construct) => $app->register(new RoutingServiceProvider($app)) => RoutingServiceProvider->register()->registerRouter()

protected function registerRouter(){    $this->app['router'] = $this->app->share(function ($app) {        return new Router($app['events'], $app);    });}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Unresolved

流水线怎么调用中间件,怎么派发给路由器,路由器又是怎么工作的呢?这中间有很多细节还没搞明白。

流水线那里,代码很绕,暂时无法理解。中间件那里,文档太简陋,暂时无法理解。路由器运行原理那里,暂时还没有去看代码。

目前就是这个样子,此文到此为止吧。我想我需要去看一下Laravel 5.1的基础文档,然后再回头去读源码,可能效果会更好。

补记

Bootstrap

我之前在分析Kernel::handle()时,忽略了一个地方,Kernel::sendRequestThroughRouter()内部调用了Kernel::bootstrap()方法:

/** * Bootstrap the application for HTTP requests. * * @return void */public function bootstrap(){    if (! $this->app->hasBeenBootstrapped()) {        $this->app->bootstrapWith($this->bootstrappers());    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Kernel::bootstrap()内部又调用了Applicaton::bootstrapWith()

/** * Run the given array of bootstrap classes. * * @param  array  $bootstrappers * @return void */public function bootstrapWith(array $bootstrappers){    $this->hasBeenBootstrapped = true;    foreach ($bootstrappers as $bootstrapper) {        $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);        $this->make($bootstrapper)->bootstrap($this);        $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Applicaton::bootstrapWith()的参数是Kernel::bootstrappers(),其初始值为:

/** * The bootstrap classes for the application. * * @var array */protected $bootstrappers = [    'Illuminate\Foundation\Bootstrap\DetectEnvironment',    'Illuminate\Foundation\Bootstrap\LoadConfiguration',    'Illuminate\Foundation\Bootstrap\ConfigureLogging',    'Illuminate\Foundation\Bootstrap\HandleExceptions',    'Illuminate\Foundation\Bootstrap\RegisterFacades',    'Illuminate\Foundation\Bootstrap\RegisterProviders',    'Illuminate\Foundation\Bootstrap\BootProviders',];
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

以其中RegisterProviders为例,其bootstrap()方法调用了$app->registerConfiguredProviders()

public function registerConfiguredProviders(){    $manifestPath = $this->getCachedServicesPath();    (new ProviderRepository($this, new Filesystem, $manifestPath))                ->load($this->config['app.providers']);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

其中$this->config['app.providers']的值来自于文件config/app.php

'providers' => [    /*     * Laravel Framework Service Providers...     */    Illuminate\Foundation\Providers\ArtisanServiceProvider::class,    Illuminate\Auth\AuthServiceProvider::class,    Illuminate\Broadcasting\BroadcastServiceProvider::class,    Illuminate\Bus\BusServiceProvider::class,    Illuminate\Cache\CacheServiceProvider::class,    Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,    Illuminate\Routing\ControllerServiceProvider::class,    Illuminate\Cookie\CookieServiceProvider::class,    Illuminate\Database\DatabaseServiceProvider::class,    Illuminate\Encryption\EncryptionServiceProvider::class,    Illuminate\Filesystem\FilesystemServiceProvider::class,    Illuminate\Foundation\Providers\FoundationServiceProvider::class,    Illuminate\Hashing\HashServiceProvider::class,    Illuminate\Mail\MailServiceProvider::class,    Illuminate\Pagination\PaginationServiceProvider::class,    Illuminate\Pipeline\PipelineServiceProvider::class,    Illuminate\Queue\QueueServiceProvider::class,    Illuminate\Redis\RedisServiceProvider::class,    Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,    Illuminate\Session\SessionServiceProvider::class,    Illuminate\Translation\TranslationServiceProvider::class,    Illuminate\Validation\ValidationServiceProvider::class,    Illuminate\View\ViewServiceProvider::class,    /*     * Application Service Providers...     */    App\Providers\AppServiceProvider::class,    App\Providers\AuthServiceProvider::class,    App\Providers\EventServiceProvider::class,    App\Providers\RouteServiceProvider::class,],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

大家都看到了,Kernel和Application互相交叉调用,Bootstrap过程又穿插在Request处理过程中间。暂时看不出清晰的思路。

原创粉丝点击