編程學(xué)習(xí)網(wǎng) > PHP技術(shù) > laravel > laravel完整生命周期是多久
2021
08-03

laravel完整生命周期是多久

雖然關(guān)于 laravel 的生命周期的文章已經(jīng)很多了,但是也很有必要根據(jù)自己的理解分享出一篇文章來,加深下印象。

簡(jiǎn)介

Laravel的生命周期開始于 public/index.php,結(jié)束于 public/index.php。客戶端的所有請(qǐng)求都經(jīng)由Web服務(wù)器引導(dǎo)到這個(gè)文件中。以下是public/index.php 文件的源碼和注釋:

#public/index.php 文件

// 定義了laravel一個(gè)請(qǐng)求的開始時(shí)間
define('LARAVEL_START', microtime(true));

// composer自動(dòng)加載機(jī)制,加載項(xiàng)目依賴
require __DIR__.'/../vendor/autoload.php';

// 這句話你就可以理解laravel,在最開始引入了一個(gè)ioc容器。
$app = require_once __DIR__.'/../bootstrap/app.php';

// 這個(gè)相當(dāng)于我們創(chuàng)建了Kernel::class的服務(wù)提供者
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

// 獲取一個(gè) Request ,返回一個(gè) Response。以把該內(nèi)核想象作一個(gè)代表整個(gè)應(yīng)用的大黑盒子,輸入 HTTP 請(qǐng)求,返回 HTTP 響應(yīng)
// 處理請(qǐng)求
$response = $kernel->handle(
    // 創(chuàng)建請(qǐng)求實(shí)例
    $request = Illuminate\Http\Request::capture()
);

// 發(fā)送響應(yīng),就是把我們服務(wù)器的結(jié)果返回給瀏覽器。
$response->send();

// 終止程序,這個(gè)就是執(zhí)行我們比較耗時(shí)的請(qǐng)求,
$kernel->terminate($request, $response);

由上可知 Laravel 的生命周期分為以下3個(gè)主要階段:


?加載項(xiàng)目依賴。

?創(chuàng)建Laravel應(yīng)用實(shí)例

?接收請(qǐng)求并響應(yīng)。


接下來我們根據(jù) public/index.php 文件,開始 Laravel 的生命周期之旅吧!


一、Composer 自動(dòng)加載項(xiàng)目依賴

// composer自動(dòng)加載機(jī)制
require __DIR__.'/../vendor/autoload.php';

Composer 是 PHP 的包管理器,用來管理項(xiàng)目依賴的工具,autoload.php 中引入了 Composer 自動(dòng)生成的加載程序,實(shí)現(xiàn)加載第三方依賴。


autoload.php 文件代碼:

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit101671ca9bbc2f62f8335eb842637291::getLoader();

二、創(chuàng)建應(yīng)用實(shí)例

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

bootstrap/app.php 文件代碼:

// 創(chuàng)建Laravel應(yīng)用的ioc容器,
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
// 完成內(nèi)核的綁定
$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
);
// 返回實(shí)例
return $app;

如果你理解了 Ioc(控制反轉(zhuǎn)),那么對(duì)于以上代碼你一定很熟悉。


Ioc 容器(服務(wù)容器) 是 Laravel 的核心,這一階段主要實(shí)現(xiàn)了 2大功能:

1、創(chuàng)建容器

2、綁定內(nèi)核


創(chuàng)建容器


$app = new Illuminate\Foundation\Application(

   $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)

);


我們進(jìn)入 Illuminate\Foundation\Application 容器中,以下是構(gòu)造函數(shù)的分析:


/**

    * Create a new Illuminate application instance.

    *

    * @param  string|null  $basePath

    * @return void

    */

   public function __construct($basePath = null)

   {

       if ($basePath) {

           // 1、路徑綁定

           $this->setBasePath($basePath);

       }

       // 2、基礎(chǔ)綁定

       $this->registerBaseBindings();

       // 3、基礎(chǔ)服務(wù)提供者綁定(事件,日志,路由)

       $this->registerBaseServiceProviders();

       // 4、核心別名綁定,目的是給核心的類命名空間設(shè)置別名,以便后續(xù)使用

       $this->registerCoreContainerAliases();

   }


綁定內(nèi)核


// 完成內(nèi)核的綁定

// HTTP內(nèi)核

$app->singleton(

   Illuminate\Contracts\Http\Kernel::class,

   App\Http\Kernel::class

);

// Console內(nèi)核

$app->singleton(

   Illuminate\Contracts\Console\Kernel::class,

   App\Console\Kernel::class

);

// 綁定異常處理

$app->singleton(

   Illuminate\Contracts\Debug\ExceptionHandler::class,

   App\Exceptions\Handler::class

);


在 Laravel 中只要是通過 public/index.php 來啟動(dòng)框架的,都會(huì)用到 Http Kernel(主要作用就是接受請(qǐng)求并返回響應(yīng)),而其他的例如通過 artisan 命令、計(jì)劃任務(wù)、隊(duì)列等啟動(dòng)框架進(jìn)行處理的都會(huì)用到 Console 內(nèi)核。


其中 HTTP 內(nèi)核類繼承 Illuminate\Foundation\Http\Kernel ,HTTP內(nèi)核類中定義了中間件相關(guān)數(shù)組,中間件主要是提供了一種方便機(jī)制用來過濾進(jìn)入應(yīng)用的請(qǐng)求和處理HTTP響應(yīng)。


HTTP 內(nèi)核類:


<?php



namespace App\Http;



use Illuminate\Foundation\Http\Kernel as HttpKernel;



class Kernel extends HttpKernel

{

   /**

    * The application's global HTTP middleware stack.

    *

    * These middleware are run during every request to your application.

    *

    * @var array

    */

   protected $middleware = [

       \App\Http\Middleware\TrustProxies::class,

       \App\Http\Middleware\CheckForMaintenanceMode::class,

       \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,

       \App\Http\Middleware\TrimStrings::class,

       \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,

   ];



   /**

    * The application's route middleware groups.

    *

    * @var array

    */

   protected $middlewareGroups = [

       'web' => [

           \App\Http\Middleware\EncryptCookies::class,

           \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,

           \Illuminate\Session\Middleware\StartSession::class,

           // \Illuminate\Session\Middleware\AuthenticateSession::class,

           \Illuminate\View\Middleware\ShareErrorsFromSession::class,

           \App\Http\Middleware\VerifyCsrfToken::class,

           \Illuminate\Routing\Middleware\SubstituteBindings::class,

       ],



       'api' => [

           'throttle:60,1',

           'bindings',

       ],

   ];



   /**

    * The application's route middleware.

    *

    * These middleware may be assigned to groups or used individually.

    *

    * @var array

    */

   protected $routeMiddleware = [

       'auth' => \App\Http\Middleware\Authenticate::class,

       'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,

       'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,

       'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,

       'can' => \Illuminate\Auth\Middleware\Authorize::class,

       'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,

       'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,

       'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,

       'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,

   ];



   /**

    * The priority-sorted list of middleware.

    *

    * This forces non-global middleware to always be in the given order.

    *

    * @var array

    */

   protected $middlewarePriority = [

       \Illuminate\Session\Middleware\StartSession::class,

       \Illuminate\View\Middleware\ShareErrorsFromSession::class,

       \App\Http\Middleware\Authenticate::class,

       \Illuminate\Session\Middleware\AuthenticateSession::class,

       \Illuminate\Routing\Middleware\SubstituteBindings::class,

       \Illuminate\Auth\Middleware\Authorize::class,

   ];

}


HTTP內(nèi)核類的父類:Illuminate\Foundation\Http\Kernel 提供了名為 $bootstrappers 的引導(dǎo)程序數(shù)組,包括了環(huán)境檢測(cè)、加載配置、處理異常、Facades注冊(cè)、服務(wù)提供者注冊(cè)、啟動(dòng)服務(wù)這6個(gè) 程序。


/**

    * The bootstrap classes for the application.

    *

    * @var array

    */

   protected $bootstrappers = [

       \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,

       \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,

       \Illuminate\Foundation\Bootstrap\HandleExceptions::class,

       \Illuminate\Foundation\Bootstrap\RegisterFacades::class,

       \Illuminate\Foundation\Bootstrap\RegisterProviders::class,

       \Illuminate\Foundation\Bootstrap\BootProviders::class,

   ];


Console 內(nèi)核:

一個(gè)健壯的應(yīng)用程序除了滿足網(wǎng)絡(luò)請(qǐng)求外,還應(yīng)該包括執(zhí)行計(jì)劃任務(wù)、異步隊(duì)列等,Laravel中通過artisan工具定義各種命令來完成非 HTTP 請(qǐng)求的各種場(chǎng)景。artisan命令通過 Laravel 的 Console 內(nèi)核完成對(duì)應(yīng)用核心組件的調(diào)度來完成任務(wù)。Console 內(nèi)核在這不做詳細(xì)介紹。


綁定異常處理

異常處理由 App\Exceptions\Handler 類完成,所有的異常處理都由其處理,在這里同樣不做詳細(xì)介紹。


三、接收請(qǐng)求并響應(yīng)

解析內(nèi)核


$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);


這里將 HTTP 內(nèi)核解析出來,我們進(jìn)一步查看Illuminate\Contracts\Http\Kernel::class 的內(nèi)部代碼,


構(gòu)造函數(shù)中注入了app容器和路由器2個(gè)函數(shù),在實(shí)例化內(nèi)核的過程中,將內(nèi)核中定義的中間件注冊(cè)到路由器中,注冊(cè)完成后便可以處理HTTP請(qǐng)求前調(diào)用中間件 實(shí)現(xiàn)過濾請(qǐng)求的目的。


Illuminate\Foundation\Http\Kernel 的構(gòu)造函數(shù):


/**

    * Create a new HTTP kernel instance.

    *

    * @param  \Illuminate\Contracts\Foundation\Application  $app

    * @param  \Illuminate\Routing\Router  $router

    * @return void

    */

   public function __construct(Application $app, Router $router)

   {

       $this->app = $app;

       $this->router = $router;



       $router->middlewarePriority = $this->middlewarePriority;



       foreach ($this->middlewareGroups as $key => $middleware) {

           $router->middlewareGroup($key, $middleware);

       }



       foreach ($this->routeMiddleware as $key => $middleware) {

           $router->aliasMiddleware($key, $middleware);

       }

   }



// Illuminate\Routing\Router 類中



/**

    * Register a group of middleware.

    *

    * @param  string  $name

    * @param  array  $middleware

    * @return $this

    */

   public function middlewareGroup($name, array $middleware)

   {

       $this->middlewareGroups[$name] = $middleware;



       return $this;

   }



/**

    * Register a short-hand name for a middleware.

    *

    * @param  string  $name

    * @param  string  $class

    * @return $this

    */

   public function aliasMiddleware($name, $class)

   {

       $this->middleware[$name] = $class;



       return $this;

   }


處理 HTTP 請(qǐng)求


// handle 方法處理請(qǐng)求

$response = $kernel->handle(

   // 創(chuàng)建請(qǐng)求實(shí)例

   $request = Illuminate\Http\Request::capture()

);


創(chuàng)建請(qǐng)求實(shí)例:在處理請(qǐng)求過程之前會(huì)通過 Illuminate\Http\Request 的 capture 方法,以進(jìn)入應(yīng)用的HTTP請(qǐng)求信息為基礎(chǔ),創(chuàng)建出一個(gè) Laravel Request請(qǐng)求實(shí)例,在后續(xù)應(yīng)用剩余的生命周期中Request請(qǐng)求實(shí)例就是對(duì)本次HTTP請(qǐng)求的抽象。


/**

    * Create a new Illuminate HTTP request from server variables.

    *

    * @return static

    */

   public static function capture()

   {

       static::enableHttpMethodParameterOverride();



       return static::createFromBase(SymfonyRequest::createFromGlobals());

   }



/**

    * Creates a new request with values from PHP's super globals.

    *

    * @return static

    */

   public static function createFromGlobals()

   {

       $request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER);



       if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')

           && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH'])

       ) {

           parse_str($request->getContent(), $data);

           $request->request = new ParameterBag($data);

       }



       return $request;

   }


handle 處理請(qǐng)求:將 HTTP 請(qǐng)求抽象成 Laravel Request 請(qǐng)求實(shí)例后,請(qǐng)求實(shí)例會(huì)被傳導(dǎo)進(jìn)入到HTTP內(nèi)核的 handle 方法內(nèi)部,請(qǐng)求的處理就是由 handle 方法來完成的。


namespace Illuminate\Foundation\Http;



class Kernel implements KernelContract

{

   /**

    * Handle an incoming HTTP request.

    *

    * @param  \Illuminate\Http\Request  $request

    * @return \Illuminate\Http\Response

    */

   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) {

           $this->reportException($e = new FatalThrowableError($e));

           $response = $this->renderException($request, $e);

       }

       $this->app['events']->dispatch(

           new Events\RequestHandled($request, $response)

       );

       return $response;

   }

}


handle 方法接收了一個(gè)請(qǐng)求,并在最后返回了一個(gè) HTTP響應(yīng)。

接下來進(jìn)入 sendRequestThroughRouter 方法,通過中間件/路由器發(fā)送給定的請(qǐng)求。

該方法的程序執(zhí)行如下:

1、將 request 請(qǐng)求實(shí)例注冊(cè)到 app 容器當(dāng)中

2、清除之前的 request 實(shí)例緩存

3、啟動(dòng)引導(dǎo)程序:加載內(nèi)核中定義的引導(dǎo)程序來引導(dǎo)啟動(dòng)應(yīng)用

4、將請(qǐng)求發(fā)送到路由:通過 Pipeline 對(duì)象傳輸 HTTP請(qǐng)求對(duì)象流經(jīng)框架中定義的HTTP中間件和路由器來完成過濾請(qǐng)求,最終將請(qǐng)求傳遞給處理程序(控制器方法或者路由中的閉包)由處理程序返回相應(yīng)的響應(yīng)。


/**

    * 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();



       return (new Pipeline($this->app))

                   ->send($request)

                   ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)

                   ->then($this->dispatchToRouter());

   }


bootstrap 引導(dǎo)程序


/**

    * Bootstrap the application for HTTP requests.

    *

    * @return void

    */

   public function bootstrap()

   {

       if (! $this->app->hasBeenBootstrapped()) {

           $this->app->bootstrapWith($this->bootstrappers());

       }

   }

/**

    * Get the bootstrap classes for the application.

    *

    * @return array

    */

   protected function bootstrappers()

   {

       return $this->bootstrappers;

   }



/**

    * The bootstrap classes for the application.

    *

    * @var array

    */

   protected $bootstrappers = [

       \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,

       \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,

       \Illuminate\Foundation\Bootstrap\HandleExceptions::class,

       \Illuminate\Foundation\Bootstrap\RegisterFacades::class,

       \Illuminate\Foundation\Bootstrap\RegisterProviders::class,

       \Illuminate\Foundation\Bootstrap\BootProviders::class,

   ];

/*引導(dǎo)啟動(dòng)Laravel應(yīng)用程序

1. DetectEnvironment  檢查環(huán)境

2. LoadConfiguration  加載應(yīng)用配置

3. ConfigureLogging   配置日至

4. HandleException    注冊(cè)異常處理的Handler

5. RegisterFacades    注冊(cè)Facades

6. RegisterProviders  注冊(cè)Providers

7. BootProviders      啟動(dòng)Providers

*/


關(guān)于引導(dǎo)程序的啟動(dòng)原理,有時(shí)間我們?cè)俪槌鰜砜纯础?


發(fā)送響應(yīng)


$response->send();


經(jīng)過了以上階段,終于獲取到了我們想要的數(shù)據(jù),接下來是將數(shù)據(jù)響應(yīng)到客戶端。


程序由在 Illuminate\Http\Response 內(nèi)部由其父類 Symfony\Component\HttpFoundation\Response 的 send() 方法實(shí)現(xiàn)。


/**

    * Sends HTTP headers and content.

    *

    * @return $this

    */

   public function send()

   {

       $this->sendHeaders(); // 發(fā)送頭部信息

       $this->sendContent(); // 發(fā)送報(bào)文主題



       if (\function_exists('fastcgi_finish_request')) {

           fastcgi_finish_request();

       } elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {

           static::closeOutputBuffers(0, true);

       }

       return $this;

   }


四、終止應(yīng)用程序


該過程調(diào)用終止中間件。

響應(yīng)完成后,HTTP 內(nèi)核會(huì)調(diào)用 terminate 中間件做一些后續(xù)的處理工作。比如,Laravel 內(nèi)置的 session 中間件會(huì)在響應(yīng)發(fā)送到瀏覽器之后將會(huì)話數(shù)據(jù)寫入存儲(chǔ)器中。

HTTP 內(nèi)核的 terminate 方法會(huì)調(diào)用 terminate 中間件的 terminate 方法,調(diào)用完成后,整個(gè)生命周期結(jié)束。


$kernel->terminate($request, $response);



/**

    * Call the terminate method on any terminable middleware.

    *

    * @param  \Illuminate\Http\Request  $request

    * @param  \Illuminate\Http\Response  $response

    * @return void

    */

   public function terminate($request, $response)

   {

       $this->terminateMiddleware($request, $response);



       $this->app->terminate();

   }

/**

    * Call the terminate method on any terminable middleware.

    *

    * @param  \Illuminate\Http\Request  $request

    * @param  \Illuminate\Http\Response  $response

    * @return void

    */

   protected function terminateMiddleware($request, $response)

   {

       $middlewares = $this->app->shouldSkipMiddleware() ? [] : array_merge(

           $this->gatherRouteMiddleware($request),

           $this->middleware

       );



       foreach ($middlewares as $middleware) {

           if (! is_string($middleware)) {

               continue;

           }



           [$name] = $this->parseMiddleware($middleware);



           $instance = $this->app->make($name);



           if (method_exists($instance, 'terminate')) {

               $instance->terminate($request, $response);

           }

       }

   }


五、總結(jié)


在Laravel 的整個(gè)生命周期中,加載項(xiàng)目依賴、創(chuàng)建應(yīng)用實(shí)例、接收并響應(yīng)請(qǐng)求,終止程序,內(nèi)核都起到了串聯(lián)作用。

首先,創(chuàng)建 Laravel 應(yīng)用程序 階段時(shí),包含了注冊(cè)項(xiàng)目基礎(chǔ)服務(wù)、注冊(cè)項(xiàng)目服務(wù)提供者別名、注冊(cè)目錄路徑、異常類綁定等工作,同時(shí)在HTTP 內(nèi)核中配置了引導(dǎo)程序。接著,在 接收請(qǐng)求并響應(yīng) 階段時(shí),會(huì)根據(jù)運(yùn)行的環(huán)境解析出 HTTP 內(nèi)核或 Console 內(nèi)核。在 HTTP 內(nèi)核中把中間件注冊(cè)到路由器中。然后,處理請(qǐng)求階段的過程中,將請(qǐng)求的實(shí)例注冊(cè)到app容器中,通過引導(dǎo)程序啟動(dòng)應(yīng)用,最后發(fā)送請(qǐng)求到路由。之后,通過Response類響應(yīng)數(shù)據(jù)。最后,通過terminate 方法終止程序。

以上就是關(guān)于 Laravel 生命周期的詳細(xì)解析。想要獲取更多laravel教程歡迎關(guān)注編程學(xué)習(xí)網(wǎng)

掃碼二維碼 獲取免費(fèi)視頻學(xué)習(xí)資料

Python編程學(xué)習(xí)

查 看2022高級(jí)編程視頻教程免費(fèi)獲取