安裝,和建立項目,都是經過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還十分陌生的狀況下。適可而止是理智的選擇。
仍是先看一下基礎性的文檔吧: