安装,和建立项目,都是经过Composer,简单,略过。php
网站入口文件,${Laravel-project}/public/index.PHP:laravel
$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);
生成Request,处理Request(Http\Kernel::handle()
),生成Response,发送Resonse。常规的Web处理流程。docker
注意 Illuminate\Contracts\Http\Kernel
只是一个Interface:bootstrap
interface Kernel { public function bootstrap(); public function handle($request); public function terminate($request, $response); public function getApplication(); }
可见入口文件中的代码,$kernel = $app->make
是关键,后面都是调用Kerenl接口的实例对象方法(特别是Kernel::handle()
)。数组
但是 $app 是谁建立的呢?是什么类型呢?闭包
入口文件的第一行代码:并发
$app = require_once __DIR__.'/../bootstrap/app.php';
引导咱们去查看 bootstrap/app.php 源码,代码很少,都拿过来看看吧:app
$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;
第一行建立,最后一行返回。如今咱们知道啦,$app
是Illuminate\Foundation\Application
类型的对象。(由于require_once
,$app
是一个单实例对象。中间几行代码后面可能有用,此处暂时忽略。)框架
天然,$kernel = $app->make()
也就是调用Applicaton::make()
了,代码拿来看一下:ide
/** * 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); }
然而仍是不清楚它具体返回哪一个类型。
对照前面bootstrap的代码:
$app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class );
咱们推论得出:$kernel = $app->make()
的真实类型是App\Http\Kernel
(同时实现了接口Illuminate\Contracts\Http\Kernel
)。
这个推论很容易被证明,此处省略细节($app->singleton->bind->alias->make())。
更加具体的建立Kernel对象的细节十分琐碎,咱们也一并忽略,有兴趣的能够去看父类方法Illuminate\Container\Container::make()/build()
的代码。
如今咱们初步总结一下:先new出Application类型对象app,app建立Kernel类型对象kernel,kernel处理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); }
下一步我想知道 $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; }
上面代码中我感兴趣的只有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()); }
上面代码中最后一行是咱们关注的重点,它把Request送进一个新建立的流水线(Pipeline),
供各个中间件(Middleware)处理,而后再派发给路由器(Router)。下文将展开分析。
流水线,中间件,路由器。
流水线Illuminate\Pipeline\Pipeline
实现了接口Illuminate\Contracts\Pipeline\Pipeline
。
其主要接口方法有send
,through
,via
,then
。其中send
设置Request对象,through
设置中间件数组,via
设置方法名(默认为”handle”),then
最终运行此并执行闭包参数(then
的代码极其复杂,各类闭包嵌套,把我搞糊涂了,有兴趣的朋友能够看一下)。
简单推断来讲,其工做内容是:依次调用各中间件的handle
方法。特别的,若是某个中间件是闭包,以闭包的形式调用之。
中间件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); }
其文档也极其简陋,看不出太多有价值的信息。第二个参数什么意思,返回值什么意思,鬼才能看出来。可能须要从其余地方入手研究中间件。
将请求派发给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); }); }
流水线怎么调用中间件,怎么派发给路由器,路由器又是怎么工做的呢?这中间有不少细节还没搞明白。
流水线那里,代码很绕,暂时没法理解。中间件那里,文档太简陋,暂时没法理解。路由器运行原理那里,暂时尚未去看代码。
目前就是这个样子,此文到此为止吧。我想我须要去看一下Laravel 5.1的基础文档,而后再回头去读源码,可能效果会更好。
我以前在分析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()); } }
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]); } }
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', ];
以其中RegisterProviders
为例,其bootstrap()
方法调用了$app->registerConfiguredProviders()
:
public function registerConfiguredProviders() { $manifestPath = $this->getCachedServicesPath(); (new ProviderRepository($this, new Filesystem, $manifestPath)) ->load($this->config['app.providers']); }
其中$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, ],
你们都看到了,Kernel和Application互相交叉调用,Bootstrap过程又穿插在Request处理过程当中间。暂时看不出清晰的思路。
Laravel不是一个小项目,逻辑复杂,划分模块以后,布局分散。你很难在短期内仅仅经过浏览源代码理清框架主体设计思路,尤为是在本人对Laravel还十分陌生的状况下。适可而止是理智的选择。
仍是先看一下基础性的文档吧: