入口文件 index.phpphp
Illuminate\Foundation\Application 類web
注入全部基礎 Service Providerbootstrap
入口文件 index.php數組
一個基於Laravel的應用,當WEB服務器接受到來自外部的請求後,會將這個這個請求解析到 應用根目錄的 public/index.php 中。服務器
<?php /** * Laravel - A PHP Framework For Web Artisans * * @package Laravel * @author Taylor Otwell <taylorotwell@gmail.com> */ /* |-------------------------------------------------------------------------- | Register The Auto Loader |-------------------------------------------------------------------------- | | Composer provides a convenient, automatically generated class loader for | our application. We just need to utilize it! We'll simply require it | into the script here so that we don't have to worry about manual | loading any of our classes later on. It feels nice to relax. | */ require __DIR__.'/../bootstrap/autoload.php'; /* |-------------------------------------------------------------------------- | Turn On The Lights |-------------------------------------------------------------------------- | | We need to illuminate PHP development, so let us turn on the lights. | This bootstraps the framework and gets it ready for use, then it | will load up this application so that we can run it and send | the responses back to the browser and delight our users. | */ $app = require_once __DIR__.'/../bootstrap/app.php'; /* |-------------------------------------------------------------------------- | Run The Application |-------------------------------------------------------------------------- | | Once we have the application, we can handle the incoming request | through the kernel, and send the associated response back to | the client's browser allowing them to enjoy the creative | and wonderful application we have prepared for them. | */ $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ); $response->send(); $kernel->terminate($request, $response);
第二十一行代碼app
require __DIR__.'/../bootstrap/autoload.php';
ide
爲Laravel應用引入了由Composer提供的類加載器,這樣Laravel應用便無需再手動加載任 何的類。其加載原理不是這次探究的目標,因此僅僅這樣使用就行了。接下的代碼,即是重 點。函數
Illuminate\Foundation\Application 類ui
該類的繼承結構以下:this
第三十五行代碼
$app = require_once __DIR__.'/../bootstrap/app.php';
它將個人視線引入到了另一個文件中,去看看到底發生了什麼吧
<?php /* |-------------------------------------------------------------------------- | Create The Application |-------------------------------------------------------------------------- | | The first thing we will do is create a new Laravel application instance | which serves as the "glue" for all the components of Laravel, and is | the IoC container for the system binding all of the various parts. | */ $app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') ); /* |-------------------------------------------------------------------------- | Bind Important Interfaces |-------------------------------------------------------------------------- | | Next, we need to bind some important interfaces into the container so | we will be able to resolve them when needed. The kernels serve the | incoming requests to this application from both the web and CLI. | */ $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 The Application |-------------------------------------------------------------------------- | | This script returns the application instance. The instance is given to | the calling script so we can separate the building of the instances | from the actual running of the application and sending responses. | */ return $app;
看第十四行,原來$app是一個 Illuminate\Foundation\Application 對象,那麼在創 建這個對象的時候又發生了什麼呢?
從它的構造方法看起:
/** * Create a new Illuminate application instance. * * @param string|null $basePath * @return void */ public function __construct($basePath = null) { $this->registerBaseBindings(); $this->registerBaseServiceProviders(); $this->registerCoreContainerAliases(); if ($basePath) { $this->setBasePath($basePath); } }
順着函數調用,往下看。在這個構造函數中,首先調用了registerBaseBindings方法。
/** * Register the basic bindings into the container. * * @return void */ protected function registerBaseBindings() { static::setInstance($this); $this->instance('app', $this); $this->instance('Illuminate\Container\Container', $this); }
這段代碼,是將實例對象注入到容器中。那麼,這個容器是什麼呢?答案仍是要從這段調用 中去尋找。
static::setInstance($this) 所作的就是將 $this 賦值給自身的 instance 靜態變 量。重點看 $this->instance('app', $this)。
instance 函數的做用是綁定一個已有對象到容器中,這個對象在容器中共享而且能夠通 過鍵獲取。
/** * Register an existing instance as shared in the container. * * @param string $abstract * @param mixed $instance * @return void */ public function instance($abstract, $instance) { if (is_array($abstract)) { // $abstract 是這樣的一個數組 ['actual key' => 'alias'] list($abstract, $alias) = $this->extractAlias($abstract); // 實際上的行爲是 $this->aliases[$alias] = $abstract; $this->alias($abstract, $alias); } unset($this->aliases[$abstract]); // 檢查是否有這個鍵是否已經註冊到容器中 // $bound 是一個boolean值 $bound = $this->bound($abstract); $this->instances[$abstract] = $instance; if ($bound) { $this->rebound($abstract); } }
視線從新回到Application類中,接下來調用了這個方法 $this->registerBaseServiceProviders()
/** * Register all of the base service providers. * * @return void */ protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); $this->register(new RoutingServiceProvider($this)); } /** * Register a service provider with the application. * * @param \Illuminate\Support\ServiceProvider|string $provider * @param array $options * @param bool $force * @return \Illuminate\Support\ServiceProvider */ public function register($provider, $options = [], $force = false) { if ($registered = $this->getProvider($provider) && !$force) { return $registered; } // If the given "provider" is a string, we will resolve it, passing in the // application instance automatically for the developer. This is simply // a more convenient way of specifying your service provider classes. if (is_string($provider)) { $provider = $this->resolveProviderClass($provider); } $provider->register(); // Once we have registered the service we will iterate through the options // and set each of them on the application so they will be available on // the actual loading of the service objects and for developer usage. foreach ($options as $key => $value) { $this[$key] = $value; } $this->markAsRegistered($provider); // If the application has already booted, we will call this boot method on // the provider class so it has an opportunity to do its boot logic and // will be ready for any usage by the developer's application logics. if ($this->booted) { $this->bootProvider($provider); } return $provider; }
其中,EventServiceProvider和RoutingServiceProvider分別是
Illuminate\Events\EventServiceProvider
Illuminate\Routing\RoutingServiceProvider
這些ServiceProvider是 Illuminate\Support\ServiceProvider 的子類,它接受一個 Application 對象做爲構造函數參數,存儲在實例變量 $app 中。
注入全部基
首頁是在Laravel中接觸的最多的 route 被註冊,它是 Illuminate\Routing\Router 對象。
礎 Service Provider
在 register 方法中,每一個ServiceProvider被調用了自身的 register 方法。首先看 看 EventServiceProvider 中的吧。
public function register() { $this->app->singleton('events', function ($app) { return (new Dispatcher($app))->setQueueResolver(function () use ($app) { return $app->make('Illuminate\Contracts\Queue\Factory'); }); }); }
上面方法體將一個 Illuminate\Events\Dispatcher 對象以鍵 events 綁定到了容器 中,它負責實現事件的調度。
再看看 Illuminate\Routing\RoutingServiceProvider:
public function register() { $this->registerRouter(); $this->registerUrlGenerator(); $this->registerRedirector(); $this->registerPsrRequest(); $this->registerPsrResponse(); $this->registerResponseFactory(); }
首頁是在Laravel中接觸的最多的 route 被註冊,它是 Illuminate\Routing\Router 對象。