亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

深度挖掘 Laravel 生命周期

arashicage / 531人閱讀

摘要:引導(dǎo)程序包括完成環(huán)境檢測(cè)配置加載異常處理注冊(cè)服務(wù)提供者注冊(cè)啟動(dòng)服務(wù)這六個(gè)引導(dǎo)程序。處理請(qǐng)求請(qǐng)求處理發(fā)生在內(nèi)核的方法內(nèi)。發(fā)送響應(yīng)頭部信息發(fā)送報(bào)文主題終止程序程序終止,完成終止中間件的調(diào)用終止中間件以上便是的請(qǐng)求生命周期的始末。

本文首發(fā)于個(gè)人博客 深度挖掘 Laravel 生命周期,轉(zhuǎn)載請(qǐng)注明出處。

這篇文章我們來(lái)聊聊 「Laravel 生命周期」 這個(gè)主題。雖然網(wǎng)絡(luò)上已經(jīng)有很多關(guān)于這個(gè)主題的探討,但這個(gè)主題依然值得我們?nèi)パ芯亢蛯W(xué)習(xí)。

我想說(shuō)的是當(dāng)我們?cè)跊Q定使用某項(xiàng)技術(shù)的時(shí)候,除了需要了解它能「做什么」,其實(shí)還應(yīng)當(dāng)研究它是「怎么做的」。

Laravel 框架或者說(shuō)任何一個(gè) Web 項(xiàng)目,我們都需要理解它究竟是如何接收到用戶發(fā)起的 HTTP 請(qǐng)求的;又是如何響應(yīng)結(jié)果給用戶的;在處理請(qǐng)求和響應(yīng)的過(guò)程中都存在哪些處理值得深入學(xué)習(xí)。

所有這些內(nèi)容其實(shí)都包含在 「Laravel 生命周期」 這個(gè)主題里面。

本文較長(zhǎng)建議使用合適的 IDE 進(jìn)行代碼查閱;或者通過(guò)文中的鏈接,或是代碼注釋的 「@see」部分直接在 Github 暢讀代碼。

目錄結(jié)構(gòu)

一 摘要

二 生命周期之始末

2.1 加載項(xiàng)目依賴

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

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

2.2.2 內(nèi)核綁定

2.2.3 注冊(cè)異常處理

2.2.4 小結(jié)

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

2.3.1 解析內(nèi)核實(shí)例

2.3.2 處理 HTTP 請(qǐng)求

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

2.3.2.2 處理請(qǐng)求

2.3.2.2.1 啟動(dòng)「引導(dǎo)程序」

2.3.2.2.2 發(fā)送請(qǐng)求至路由

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

2.5 終止程序

三 總結(jié)

四 生命周期流程圖

參考資料

一 摘要

Laravel 生命周期(或者說(shuō)請(qǐng)求生命周期)概括起來(lái)主要分為 3 個(gè)主要階段:

加載項(xiàng)目依賴

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

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

而這 3 個(gè)階段的處理都發(fā)生在入口文件 public/index.php 文件內(nèi)(public/index.php 是一個(gè)新安裝的 Laravel 項(xiàng)目默認(rèn)入口文件)。

然而 index.php 文件僅包含極少的代碼,但卻出色的完成了一個(gè) HTTP 請(qǐng)求從接收到響應(yīng)的全部過(guò)程,邏輯組織的幾近完美。

我們來(lái)看下入口文件實(shí)現(xiàn)的代碼:

make(IlluminateContractsHttpKernel::class);

$response = $kernel->handle(
    $request = IlluminateHttpRequest::capture()
);

$response->send();

// 其它
$kernel->terminate($request, $response);
二 生命周期之始末 2.1 加載項(xiàng)目依賴

現(xiàn)代 PHP 依賴于 Composer 包管理器,入口文件通過(guò)引入由 Composer 包管理器自動(dòng)生成的類加載程序,可以輕松注冊(cè)并加載項(xiàng)目所依賴的第三方組件庫(kù)。

所有組件的加載工作,僅需一行代碼即可完成:

require __DIR__."/../vendor/autoload.php";
2.2 創(chuàng)建 Laravel 應(yīng)用實(shí)例

創(chuàng)建應(yīng)用實(shí)例(或稱服務(wù)容器),由位于 bootstrap/app.php 文件里的引導(dǎo)程序完成,創(chuàng)建服務(wù)容器的過(guò)程即為應(yīng)用初始化的過(guò)程,項(xiàng)目初始化時(shí)將完成包括:注冊(cè)項(xiàng)目基礎(chǔ)服務(wù)、注冊(cè)項(xiàng)目服務(wù)提供者別名、注冊(cè)目錄路徑等在內(nèi)的一些列注冊(cè)工作。

下面是 bootstrap/app.php 的代碼,包含兩個(gè)主要部分「創(chuàng)建應(yīng)用實(shí)例」和「綁定內(nèi)核至 APP 服務(wù)容器」:

singleton(
    IlluminateContractsHttpKernel::class,
    AppHttpKernel::class
);

$app->singleton(
    IlluminateContractsConsoleKernel::class,
    AppConsoleKernel::class
);

$app->singleton(
    IlluminateContractsDebugExceptionHandler::class,
    AppExceptionsHandler::class
);

return $app;
2.2.1 創(chuàng)建應(yīng)用實(shí)例

創(chuàng)建應(yīng)用實(shí)例即實(shí)例化 IlluminateFoundationApplication 這個(gè)服務(wù)容器,后續(xù)我們稱其為 APP 容器。在創(chuàng)建 APP 容器主要會(huì)完成:注冊(cè)應(yīng)用的基礎(chǔ)路徑并將路徑綁定到 APP 容器 、注冊(cè)基礎(chǔ)服務(wù)提供者至 APP 容器 、注冊(cè)核心容器別名至 APP 容器 等基礎(chǔ)服務(wù)的注冊(cè)工作。

    /**
     * Create a new Illuminate application instance.
     *
     * @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Application.php#L162:27
     * @param  string|null  $basePath
     * @return void
     */
    public function __construct($basePath = null)
    {
        if ($basePath) {
            $this->setBasePath($basePath);
        }
        $this->registerBaseBindings();
        $this->registerBaseServiceProviders();
        $this->registerCoreContainerAliases();
    }
2.2.2 內(nèi)核綁定

接著將關(guān)注的焦點(diǎn)轉(zhuǎn)移到綁定內(nèi)核部分。

Laravel 會(huì)依據(jù) HTTP 請(qǐng)求的運(yùn)行環(huán)境的不同,將請(qǐng)求發(fā)送至相應(yīng)的內(nèi)核: HTTP 內(nèi)核 或 Console 內(nèi)核。無(wú)論 HTTP 內(nèi)核還是 Console 內(nèi)核,它們的作用都是是接收一個(gè) HTTP 請(qǐng)求,隨后返回一個(gè)響應(yīng),就是這么簡(jiǎn)單。

這篇文章主要研究 HTTP 內(nèi)核,HTTP 內(nèi)核繼承自 IlluminateFoundationHttpKernel 類.

在 「HTTP 內(nèi)核」 內(nèi)它定義了 中間件 相關(guān)數(shù)組;在 「IlluminateFoundationHttpKernel」 類內(nèi)部定義了屬性名為 「bootstrappers」 的 引導(dǎo)程序 數(shù)組。

中間件 提供了一種方便的機(jī)制來(lái)過(guò)濾進(jìn)入應(yīng)用的 HTTP 請(qǐng)求。

「引導(dǎo)程序」 包括完成環(huán)境檢測(cè)、配置加載、異常處理、Facades 注冊(cè)、服務(wù)提供者注冊(cè)、啟動(dòng)服務(wù)這六個(gè)引導(dǎo)程序。

至于 「中間件」 和 「引導(dǎo)程序」如何被使用的,會(huì)在后面的章節(jié)講解。

2.2.3 注冊(cè)異常處理

項(xiàng)目的異常處理由 AppExceptionsHandler::class 類完成,這邊也不做深入的講解。

2.2.4 本節(jié)小結(jié)

通過(guò)上面的分析我們可以發(fā)現(xiàn)在「創(chuàng)建 Laravel 應(yīng)用實(shí)例」這個(gè)階段它做了很多的基礎(chǔ)工作,包括但不限于:創(chuàng)建 APP 容器、注冊(cè)應(yīng)用路徑、注冊(cè)基礎(chǔ)服務(wù)提供者、配置中間件和引導(dǎo)程序等。

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

在完成創(chuàng)建 APP 容器后即進(jìn)入了第三個(gè)階段 「接收請(qǐng)求并響應(yīng)」。

「接收請(qǐng)求并響應(yīng)」有關(guān)代碼如下:

$kernel = $app->make(IlluminateContractsHttpKernel::class);

$response = $kernel->handle(
    $request = IlluminateHttpRequest::capture()
);

$response->send();

我們需要逐行分析上面的代碼,才能窺探其中的原貌。

2.3.1 解析內(nèi)核實(shí)例

在第二階段我們已經(jīng)將 HTTP 內(nèi)核Console 內(nèi)核 綁定到了 APP 容器,使用時(shí)通過(guò) APP 容器make() 方法將內(nèi)核解析出來(lái),解析的過(guò)程就是內(nèi)核實(shí)例化的過(guò)程。

$kernel = $app->make(IlluminateContractsHttpKernel::class);

內(nèi)核實(shí)例化時(shí)它的內(nèi)部究竟又做了哪些操作呢?

進(jìn)一步挖掘 IlluminateFoundationHttpKernel 內(nèi)核的 __construct(IlluminateContractsFoundationApplication $app, IlluminateRoutingRouter $router) 構(gòu)造方法,它接收 APP 容器路由器 兩個(gè)參數(shù)。

在實(shí)例化內(nèi)核時(shí),構(gòu)造函數(shù)內(nèi)將在 HTTP 內(nèi)核定義的「中間件組」注冊(cè)到 路由器,注冊(cè)完后就可以在實(shí)際處理 HTTP 請(qǐng)求前調(diào)用這些「中間件」實(shí)現(xiàn) 過(guò)濾 請(qǐng)求的目的。

...
    /**
     * Create a new HTTP kernel instance. 創(chuàng)建 HTTP 內(nèi)核實(shí)例
     * 
     * @class IlluminateFoundationHttpKernel
     * @param  IlluminateContractsFoundationApplication  $app
     * @param  IlluminateRoutingRouter  $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);
        }
    }
...
...
    /**
     * Register a group of middleware. 注冊(cè)中間件組
     *
     * @class IlluminateRoutingRouter
     * @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. 注冊(cè)中間件別名
     *
     * @class IlluminateRoutingRouter
     * @param  string  $name
     * @param  string  $class
     * @return $this
     */
    public function aliasMiddleware($name, $class)
    {
        $this->middleware[$name] = $class;

        return $this;
    }
...
2.3.2 處理 HTTP 請(qǐng)求

之前的所有處理,基本都是圍繞在配置變量、注冊(cè)服務(wù)等運(yùn)行環(huán)境的構(gòu)建上,構(gòu)建完成后才是真刀真槍的來(lái)處理一個(gè)「HTTP 請(qǐng)求」。

處理請(qǐng)求實(shí)際包含兩個(gè)階段:

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

處理請(qǐng)求

// 處理請(qǐng)求
$response = $kernel->handle(
    // 創(chuàng)建請(qǐng)求實(shí)例
    $request = IlluminateHttpRequest::capture()
);
2.3.2.1 創(chuàng)建請(qǐng)求實(shí)例

請(qǐng)求實(shí)例 IlluminateHttpRequest 的 capture() 方法內(nèi)部通過(guò) Symfony 實(shí)例創(chuàng)建一個(gè) Laravel 請(qǐng)求實(shí)例。這樣我們就可以獲取到用戶請(qǐng)求報(bào)文的相關(guān)信息了。

    /**
     * Create a new Illuminate HTTP request from server variables.
     * 
     * @class IlluminateHttpRequest
     * @return static
     */
    public static function capture()
    {
        static::enableHttpMethodParameterOverride();
        return static::createFromBase(SymfonyRequest::createFromGlobals());
    }

    /**
     * Create an Illuminate request from a Symfony instance.
     *
     * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Request.php
     * @param  SymfonyComponentHttpFoundationRequest  $request
     * @return IlluminateHttpRequest
     */
    public static function createFromBase(SymfonyRequest $request)
    {
        if ($request instanceof static) {
            return $request;
        }

        $content = $request->content;

        $request = (new static)->duplicate(
            $request->query->all(), $request->request->all(), $request->attributes->all(),
            $request->cookies->all(), $request->files->all(), $request->server->all()
        );

        $request->content = $content;

        $request->request = $request->getInputSource();

        return $request;
    }
2.3.2.2 處理請(qǐng)求

請(qǐng)求處理發(fā)生在 HTTP 內(nèi)核 的 handle() 方法內(nèi)。

    /**
     * Handle an incoming HTTP request.
     *
     * @class IlluminateFoundationHttpKernel
     * @param  IlluminateHttpRequest  $request
     * @return IlluminateHttpResponse
     */
    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 EventsRequestHandled($request, $response)
        );

        return $response;
    }

handle() 方法接收一個(gè) HTTP 請(qǐng)求,并最終生成一個(gè) HTTP 響應(yīng)。

繼續(xù)深入到處理 HTTP 請(qǐng)求的方法 $this->sendRequestThroughRouter($request) 內(nèi)部。

    /**
     * Send the given request through the middleware / router.
     *
     * @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php
     * @param  IlluminateHttpRequest  $request
     * @return IlluminateHttpResponse
     */
    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());
    }

將發(fā)現(xiàn)這段代碼沒(méi)有一行廢話,它完成了大量的邏輯處理:

首先,將 $request 實(shí)例注冊(cè)到 APP 容器 供后續(xù)使用;

之后,清除之前 $request 實(shí)例緩存;

然后,啟動(dòng)「引導(dǎo)程序」;

最后,發(fā)送請(qǐng)求至路由。

2.3.2.2.1 啟動(dòng)「引導(dǎo)程序」

記得我們?cè)谥啊?.2.2 內(nèi)核綁定」章節(jié),有介紹在「HTTP 內(nèi)核」中有把「引導(dǎo)程序(bootstrappers)」綁定到了 APP 容器,以及這些引導(dǎo)程序的具體功能。

但是沒(méi)有聊如何調(diào)用這些「引導(dǎo)程序」。

    /**
     * Send the given request through the middleware / router.
     *
     * @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php
     * @param  IlluminateHttpRequest  $request
     * @return IlluminateHttpResponse
     */
    protected function sendRequestThroughRouter($request)
    {
        ...

        // 啟動(dòng) 「引導(dǎo)程序」
        $this->bootstrap();

        ...
    }

上面的代碼塊說(shuō)明在 $this->bootstrap(); 方法內(nèi)部有實(shí)際調(diào)用「引導(dǎo)程序」,而 bootstrap() 實(shí)際調(diào)用的是 APP 容器的 bootstrapWith(),來(lái)看看

... 
    /**
     * The bootstrap classes for the application. 應(yīng)用的引導(dǎo)程序
     *
     * @var array
     */
    protected $bootstrappers = [
        IlluminateFoundationBootstrapLoadEnvironmentVariables::class,
        IlluminateFoundationBootstrapLoadConfiguration::class,
        IlluminateFoundationBootstrapHandleExceptions::class,
        IlluminateFoundationBootstrapRegisterFacades::class,
        IlluminateFoundationBootstrapRegisterProviders::class,
        IlluminateFoundationBootstrapBootProviders::class,
    ];

    /**
     * Bootstrap the application for HTTP requests.
     * 
     * @class IlluminateFoundationHttpKernel
     * @return void
     */
    public function bootstrap()
    {
        if (! $this->app->hasBeenBootstrapped()) {
            $this->app->bootstrapWith($this->bootstrappers());
        }
    }

    protected function bootstrappers()
    {
        return $this->bootstrappers;
    }
...

最終還是要看 IlluminateFoundationApplication 的 bootstrapWith() 方法究竟如何來(lái)啟動(dòng)這些引導(dǎo)程序的。

    /**
     * Run the given array of bootstrap classes.
     * 
     * @class  IlluminateFoundationApplication APP 容器
     * @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]);
        }
    }

我們看到在 APP 容器內(nèi),會(huì)先解析對(duì)應(yīng)的「引導(dǎo)程序」(即實(shí)例化),隨后調(diào)用「引導(dǎo)程序」的 bootstrap() 完成的「引導(dǎo)程序」的啟動(dòng)操作。

作為示例我們隨便挑一個(gè)「引導(dǎo)程序」來(lái)看看其內(nèi)部的啟動(dòng)原理。

這邊我們選 IlluminateFoundationBootstrapLoadConfiguration::class,它的功能是加載配置文件。

還記得我們講解「2.2 創(chuàng)建 Laravel 應(yīng)用實(shí)例」章節(jié)的時(shí)候有「注冊(cè)應(yīng)用的基礎(chǔ)路徑并將路徑綁定到 APP 容器」。此時(shí),LoadConfiguration 類就是將 config 目錄下的所有配置文件讀取到一個(gè)集合中,這樣我們就可以項(xiàng)目里通過(guò) config() 輔助函數(shù)獲取配置數(shù)據(jù)。

getCachedConfigPath())) {
            $items = require $cached;
            $loadedFromCache = true;
        }

        $app->instance("config", $config = new Repository($items));

        if (! isset($loadedFromCache)) {
            $this->loadConfigurationFiles($app, $config);
        }

        $app->detectEnvironment(function () use ($config) {
            return $config->get("app.env", "production");
        });

        date_default_timezone_set($config->get("app.timezone", "UTC"));
        mb_internal_encoding("UTF-8");
    }

    /**
     * Load the configuration items from all of the files.
     *
     * @param  IlluminateContractsFoundationApplication  $app
     * @param  IlluminateContractsConfigRepository  $repository
     * @return void
     * @throws Exception
     */
    protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
    {
        $files = $this->getConfigurationFiles($app);

        if (! isset($files["app"])) {
            throw new Exception("Unable to load the "app" configuration file.");
        }

        foreach ($files as $key => $path) {
            $repository->set($key, require $path);
        }
    }

    ...
}

所有 「引導(dǎo)程序」列表功能如下:

IlluminateFoundationBootstrapLoadEnvironmentVariables : 環(huán)境檢測(cè),通過(guò) DOTENV 組件將 .env 配置文件載入到 $_ENV 變量中;

IlluminateFoundationBootstrapLoadConfiguration : 加載配置文件,這個(gè)我們剛剛分析過(guò);

IlluminateFoundationBootstrapHandleExceptions : 異常處理;

IlluminateFoundationBootstrapRegisterFacades : 注冊(cè) Facades,注冊(cè)完成后可以以別名的方式訪問(wèn)具體的類;

IlluminateFoundationBootstrapRegisterProviders : 注冊(cè)服務(wù)提供者,我們?cè)?「2.2.1 創(chuàng)建應(yīng)用實(shí)例」已經(jīng)將基礎(chǔ)服務(wù)提供者注冊(cè)到 APP 容器。在這里我們會(huì)將配置在 app.php 文件夾下 providers 節(jié)點(diǎn)的服務(wù)器提供者注冊(cè)到 APP 容器,供請(qǐng)求處理階段使用;

IlluminateFoundationBootstrapBootProviders : 啟動(dòng)服務(wù)

2.3.2.2.2 發(fā)送請(qǐng)求至路由

完成「引導(dǎo)程序」啟動(dòng)操作后,隨機(jī)進(jìn)入到請(qǐng)求處理階段。

    /**
     * Send the given request through the middleware / router.
     *
     * @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php
     * @param  IlluminateHttpRequest  $request
     * @return IlluminateHttpResponse
     */
    protected function sendRequestThroughRouter($request)
    {
        ...

        // 發(fā)送請(qǐng)求至路由
        return (new Pipeline($this->app))
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                    ->then($this->dispatchToRouter());
    }

在 「發(fā)送請(qǐng)求至路由」這行代碼中,完成了:管道(pipeline)創(chuàng)建、將 $request 傳入管道、對(duì) $request 執(zhí)行「中間件」處理和實(shí)際的請(qǐng)求處理四個(gè)不同的操作。

在開(kāi)始前我們需要知道在 Laravel 中有個(gè)「中間件」 的概念,即使你還不知道,也沒(méi)關(guān)系,僅需知道它的功能是在處理請(qǐng)求操作之前,對(duì)請(qǐng)求進(jìn)行過(guò)濾處理即可,僅當(dāng)請(qǐng)求符合「中間件」的驗(yàn)證規(guī)則時(shí)才會(huì)繼續(xù)執(zhí)行后續(xù)處理。

有關(guān) 「管道」的相關(guān)知識(shí)不在本文講解范圍內(nèi)。

那么,究竟一個(gè)請(qǐng)求是如何被處理的呢?

我們來(lái)看看 $this->dispatchToRouter() 這句代碼,它的方法聲明如下:

    /**
     * Get the route dispatcher callback. 獲取一個(gè)路由分發(fā)器匿名函數(shù)
     *
     * @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php
     * @return Closure
     */
    protected function dispatchToRouter()
    {
        return function ($request) {
            $this->app->instance("request", $request);

            return $this->router->dispatch($request);
        };
    }

回顧下「2.3.1 解析內(nèi)核實(shí)例」章節(jié),可知我們已經(jīng)將 IlluminateRoutingRouter 對(duì)象賦值給 $this->router 屬性。

通過(guò) router 實(shí)例的 disptach() 方法去執(zhí)行 HTTP 請(qǐng)求,在它的內(nèi)部會(huì)完成如下處理:

查找對(duì)應(yīng)的路由實(shí)例

通過(guò)一個(gè)實(shí)例棧運(yùn)行給定的路由

運(yùn)行在 routes/web.php 配置的匹配到的控制器或匿名函數(shù)

返回響應(yīng)結(jié)果

currentRequest = $request;

        return $this->dispatchToRoute($request);
    }

    /**
     * Dispatch the request to a route and return the response.
     *
     * @param  IlluminateHttpRequest  $request
     * @return mixed
     */
    public function dispatchToRoute(Request $request)
    {
        return $this->runRoute($request, $this->findRoute($request));
    }

    /**
     * Find the route matching a given request. 1. 查找對(duì)應(yīng)的路由實(shí)例
     *
     * @param  IlluminateHttpRequest  $request
     * @return IlluminateRoutingRoute
     */
    protected function findRoute($request)
    {
        $this->current = $route = $this->routes->match($request);

        $this->container->instance(Route::class, $route);

        return $route;
    }

    /**
     * Return the response for the given route. 2. 通過(guò)一個(gè)實(shí)例棧運(yùn)行給定的路由
     *
     * @param  Route  $route
     * @param  Request  $request
     * @return mixed
     */
    protected function runRoute(Request $request, Route $route)
    {
        $request->setRouteResolver(function () use ($route) {
            return $route;
        });

        $this->events->dispatch(new EventsRouteMatched($route, $request));

        return $this->prepareResponse($request,
            $this->runRouteWithinStack($route, $request)
        );
    }

    /**
     * Run the given route within a Stack "onion" instance. 通過(guò)一個(gè)實(shí)例棧運(yùn)行給定的路由
     *
     * @param  IlluminateRoutingRoute  $route
     * @param  IlluminateHttpRequest  $request
     * @return mixed
     */
    protected function runRouteWithinStack(Route $route, Request $request)
    {
        $shouldSkipMiddleware = $this->container->bound("middleware.disable") &&
                                $this->container->make("middleware.disable") === true;

        $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);

        // 4. 返回響應(yīng)結(jié)果
        return (new Pipeline($this->container))
                        ->send($request)
                        ->through($middleware)
                        ->then(function ($request) use ($route) {
                            return $this->prepareResponse(
                                // 3. 運(yùn)行在 routes/web.php 配置的匹配到的控制器或匿名函數(shù)
                                $request, $route->run()
                            );
                        });
    }

執(zhí)行 $route->run() 的方法定義在 IlluminateRoutingRoute 類中,最終執(zhí)行「在 routes/web.php 配置的匹配到的控制器或匿名函數(shù)」:

    /**
     * Run the route action and return the response.
     * 
     * @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Routing/Route.php
     * @return mixed
     */
    public function run()
    {
        $this->container = $this->container ?: new Container;

        try {
            if ($this->isControllerAction()) {
                return $this->runController();
            }

            return $this->runCallable();
        } catch (HttpResponseException $e) {
            return $e->getResponse();
        }
    }

這部分如果路由的實(shí)現(xiàn)是一個(gè)控制器,會(huì)完成控制器實(shí)例化并執(zhí)行指定方法;如果是一個(gè)匿名函數(shù)則直接調(diào)用這個(gè)匿名函數(shù)。

其執(zhí)行結(jié)果會(huì)通過(guò) IlluminateRoutingRouter::prepareResponse($request, $response) 生一個(gè)響應(yīng)實(shí)例并返回。

至此,Laravel 就完成了一個(gè) HTTP 請(qǐng)求的請(qǐng)求處理。

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

經(jīng)過(guò)一系列漫長(zhǎng)的操作,HTTP 請(qǐng)求進(jìn)入的最終章 - 發(fā)送響應(yīng)值客戶端 $response->send()。

make(IlluminateContractsHttpKernel::class);

$response = $kernel->handle(
    $request = IlluminateHttpRequest::capture()
);

// 發(fā)送響應(yīng)
$response->send();

// 其它
$kernel->terminate($request, $response);

發(fā)送響應(yīng)由 IlluminateHttpResponse 父類 SymfonyComponentHttpFoundationResponse 中的 send() 方法完成。

    /**
     * Sends HTTP headers and content.
     * 
     * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Response.php
     * @return $this
     */
    public function send()
    {
        $this->sendHeaders();// 發(fā)送響應(yīng)頭部信息
        $this->sendContent();// 發(fā)送報(bào)文主題

        if (function_exists("fastcgi_finish_request")) {
            fastcgi_finish_request();
        } elseif (!in_array(PHP_SAPI, array("cli", "phpdbg"), true)) {
            static::closeOutputBuffers(0, true);
        }
        return $this;
    }
2.5 終止程序
程序終止,完成終止中間件的調(diào)用
// @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Http/Kernel.php

public function terminate($request, $response)
{
    $this->terminateMiddleware($request, $response);
    $this->app->terminate();
}

// 終止中間件
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;
        }
        list($name, $parameters) = $this->parseMiddleware($middleware);
        $instance = $this->app->make($name);
        if (method_exists($instance, "terminate")) {
            $instance->terminate($request, $response);
        }
    }
}

以上便是 Laravel 的請(qǐng)求生命周期的始末。

三 總結(jié)

在 「創(chuàng)建 Laravel 應(yīng)用實(shí)例」時(shí)不僅會(huì)注冊(cè)項(xiàng)目基礎(chǔ)服務(wù)、注冊(cè)項(xiàng)目服務(wù)提供者別名、注冊(cè)目錄路徑等在內(nèi)的一系列注冊(cè)工作;還會(huì)綁定 HTTP 內(nèi)核及 Console 內(nèi)核到 APP 容器, 同時(shí)在 HTTP 內(nèi)核里配置中間件和引導(dǎo)程序。

進(jìn)入 「接收請(qǐng)求并響應(yīng)」里,會(huì)依據(jù)運(yùn)行環(huán)境從 APP 容器 解析出 HTTP 內(nèi)核或 Console 內(nèi)核。如果是 HTTP 內(nèi)核,還將把「中間件」及「引導(dǎo)程序」注冊(cè)到 APP 容器

所有初始化工作完成后便進(jìn)入「處理 HTTP 請(qǐng)求」階段。

一個(gè) Http 請(qǐng)求實(shí)例會(huì)被注冊(cè)到 APP 容器,通過(guò)啟動(dòng)「引導(dǎo)程序」來(lái)設(shè)置環(huán)境變量、加載配置文件等等系統(tǒng)環(huán)境配置;

隨后請(qǐng)求被分發(fā)到匹配的路由,在路由中執(zhí)行「中間件」以過(guò)濾不滿足校驗(yàn)規(guī)則的請(qǐng)求,只有通過(guò)「中間件」處理的請(qǐng)求才最終處理實(shí)際的控制器或匿名函數(shù)生成響應(yīng)結(jié)果。

最后發(fā)送響應(yīng)給用戶,清理項(xiàng)目中的中間件,完成一個(gè) 「請(qǐng)求」 - 「響應(yīng)」 的生命周期,之后我們的 Web 服務(wù)器將等待下一輪用戶請(qǐng)求。

參考資料

感謝下列優(yōu)秀的 Laravel 研究資料:

http://blog.mallow-tech.com/2...

http://laravel-recipes.com/re...

http://www.cnblogs.com/sweng/...

https://www.dyike.com/2017/04...

http://www.cnblogs.com/wxw16/...

http://www.php.cn/php-weiziji...

https://segmentfault.com/a/11...

https://segmentfault.com/a/11...

https://blog.csdn.net/cDonDon...

https://segmentfault.com/a/11...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/28672.html

相關(guān)文章

  • 深入剖析 Laravel 服務(wù)容器

    摘要:劃下重點(diǎn),服務(wù)容器是用于管理類的依賴和執(zhí)行依賴注入的工具。類的實(shí)例化及其依賴的注入,完全由服務(wù)容器自動(dòng)的去完成。 本文首發(fā)于 深入剖析 Laravel 服務(wù)容器,轉(zhuǎn)載請(qǐng)注明出處。喜歡的朋友不要吝嗇你們的贊同,謝謝。 之前在 深度挖掘 Laravel 生命周期 一文中,我們有去探究 Laravel 究竟是如何接收 HTTP 請(qǐng)求,又是如何生成響應(yīng)并最終呈現(xiàn)給用戶的工作原理。 本章將帶領(lǐng)大...

    abson 評(píng)論0 收藏0
  • Laravel 請(qǐng)求生命周期

    摘要:應(yīng)用實(shí)例所依賴的服務(wù)提供者可以在配置文件中的節(jié)點(diǎn)找到。完成所有服務(wù)提供者注冊(cè)到應(yīng)用實(shí)例后,應(yīng)用實(shí)例執(zhí)行啟動(dòng)方法引導(dǎo)項(xiàng)目啟動(dòng)。或內(nèi)核接收到請(qǐng)求,加載服務(wù)提供者,同時(shí),將請(qǐng)求分發(fā)給路由器執(zhí)行。 這是一篇翻譯文章,原文 Request Life Cycle of Laravel,譯文 Laravel 請(qǐng)求生命周期 首發(fā)于個(gè)人博客,轉(zhuǎn)載請(qǐng)注明出處。 當(dāng)需要使用一個(gè)框架、工具或者服務(wù)時(shí),在使用前...

    junfeng777 評(píng)論0 收藏0
  • Laravel學(xué)習(xí):請(qǐng)求到響應(yīng)的生命周期

    摘要:請(qǐng)求處理階段請(qǐng)求處理階段首先是準(zhǔn)備請(qǐng)求處理的環(huán)境,包括環(huán)境加載服務(wù)提供者注冊(cè)等環(huán)節(jié),然后將請(qǐng)求實(shí)例通過(guò)中間件處理及通過(guò)路由和控制器的分發(fā)控制,使得不同的請(qǐng)求通過(guò)相應(yīng)的處理程序進(jìn)行處理并生成響應(yīng)的過(guò)程。 Laravel請(qǐng)求到響應(yīng)的整個(gè)執(zhí)行過(guò)程,主要可以歸納為四個(gè)階段,即程序啟動(dòng)準(zhǔn)備階段、請(qǐng)求實(shí)例化階段、請(qǐng)求處理階段、響應(yīng)發(fā)送和程序終止階段。 程序啟動(dòng)準(zhǔn)備階段 服務(wù)容器實(shí)例化 服務(wù)容器的實(shí)...

    OBKoro1 評(píng)論0 收藏0
  • 使用 Swoole 加速 Laravel

    摘要:因?yàn)闉閱蝹€(gè)請(qǐng)求創(chuàng)建的環(huán)境將在請(qǐng)求過(guò)程完成后立即銷毀。可以成為強(qiáng)大的性能增強(qiáng)器,提供了優(yōu)雅的結(jié)構(gòu)和代碼使用方式。你可以使用此命令快速安裝它,并訪問(wèn)官方網(wǎng)站獲取更多信息。注意目前僅支持和。服務(wù)器不能使用?;鶞?zhǔn)測(cè)試使用進(jìn)行干凈的測(cè)試。 Swoole 是針對(duì)PHP的生產(chǎn)級(jí)異步編程框架。它是一種用純C語(yǔ)言編寫的PHP擴(kuò)展,它使PHP開(kāi)發(fā)人員能夠在PHP中編寫高性能,可擴(kuò)展的并發(fā)TCP,UDP,U...

    didikee 評(píng)論0 收藏0
  • 使用 Swoole 來(lái)加速你的 Laravel 應(yīng)用

    摘要:是為開(kāi)發(fā)的生產(chǎn)級(jí)異步編程框架。因?yàn)閱蝹€(gè)請(qǐng)求創(chuàng)建的環(huán)境在請(qǐng)求執(zhí)行結(jié)束后會(huì)立即銷毀??梢蕴峁?qiáng)大性能而則可以提供優(yōu)雅代碼結(jié)構(gòu)使用。在使用這個(gè)包之前,請(qǐng)確保你的機(jī)器安裝了正確的。建立并運(yùn)行起來(lái)現(xiàn)在,你可以執(zhí)行以下的命令來(lái)啟動(dòng)服務(wù)。 showImg(https://segmentfault.com/img/bVbaF89?w=1240&h=634); Swoole?是為 PHP 開(kāi)發(fā)的生產(chǎn)級(jí)異...

    snifes 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<