国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深度挖掘 Laravel 生命周期

arashicage / 474人閱讀

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

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

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

我想說的是當我們在決定使用某項技術(shù)的時候,除了需要了解它能「做什么」,其實還應(yīng)當研究它是「怎么做的」。

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

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

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

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

一 摘要

二 生命周期之始末

2.1 加載項目依賴

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

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

2.2.2 內(nèi)核綁定

2.2.3 注冊異常處理

2.2.4 小結(jié)

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

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

2.3.2 處理 HTTP 請求

2.3.2.1 創(chuàng)建請求實例

2.3.2.2 處理請求

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

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

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

2.5 終止程序

三 總結(jié)

四 生命周期流程圖

參考資料

一 摘要

Laravel 生命周期(或者說請求生命周期)概括起來主要分為 3 個主要階段:

加載項目依賴

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

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

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

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

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

make(IlluminateContractsHttpKernel::class);

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

$response->send();

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

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

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

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

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

下面是 bootstrap/app.php 的代碼,包含兩個主要部分「創(chuàng)建應(yīng)用實例」和「綁定內(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)用實例

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

    /**
     * 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)注的焦點轉(zhuǎn)移到綁定內(nèi)核部分。

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

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

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

中間件 提供了一種方便的機制來過濾進入應(yīng)用的 HTTP 請求。

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

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

2.2.3 注冊異常處理

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

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

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

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

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

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

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

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

$response->send();

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

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

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

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

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

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

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

...
    /**
     * Create a new HTTP kernel instance. 創(chuàng)建 HTTP 內(nèi)核實例
     * 
     * @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. 注冊中間件組
     *
     * @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. 注冊中間件別名
     *
     * @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 請求

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

處理請求實際包含兩個階段:

創(chuàng)建請求實例

處理請求

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

請求實例 IlluminateHttpRequest 的 capture() 方法內(nèi)部通過 Symfony 實例創(chuàng)建一個 Laravel 請求實例。這樣我們就可以獲取到用戶請求報文的相關(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 處理請求

請求處理發(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() 方法接收一個 HTTP 請求,并最終生成一個 HTTP 響應(yīng)。

繼續(xù)深入到處理 HTTP 請求的方法 $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)這段代碼沒有一行廢話,它完成了大量的邏輯處理:

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

之后,清除之前 $request 實例緩存;

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

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

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

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

但是沒有聊如何調(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ǎo)程序」
        $this->bootstrap();

        ...
    }

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

... 
    /**
     * 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() 方法究竟如何來啟動這些引導(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),會先解析對應(yīng)的「引導(dǎo)程序」(即實例化),隨后調(diào)用「引導(dǎo)程序」的 bootstrap() 完成的「引導(dǎo)程序」的啟動操作。

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

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

還記得我們講解「2.2 創(chuàng)建 Laravel 應(yīng)用實例」章節(jié)的時候有「注冊應(yīng)用的基礎(chǔ)路徑并將路徑綁定到 APP 容器」。此時,LoadConfiguration 類就是將 config 目錄下的所有配置文件讀取到一個集合中,這樣我們就可以項目里通過 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)境檢測,通過 DOTENV 組件將 .env 配置文件載入到 $_ENV 變量中;

IlluminateFoundationBootstrapLoadConfiguration : 加載配置文件,這個我們剛剛分析過;

IlluminateFoundationBootstrapHandleExceptions : 異常處理;

IlluminateFoundationBootstrapRegisterFacades : 注冊 Facades,注冊完成后可以以別名的方式訪問具體的類;

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

IlluminateFoundationBootstrapBootProviders : 啟動服務(wù)

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

完成「引導(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)
    {
        ...

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

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

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

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

那么,究竟一個請求是如何被處理的呢?

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

    /**
     * Get the route dispatcher callback. 獲取一個路由分發(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)核實例」章節(jié),可知我們已經(jīng)將 IlluminateRoutingRouter 對象賦值給 $this->router 屬性。

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

查找對應(yīng)的路由實例

通過一個實例棧運行給定的路由

運行在 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. 查找對應(yīng)的路由實例
     *
     * @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. 通過一個實例棧運行給定的路由
     *
     * @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. 通過一個實例棧運行給定的路由
     *
     * @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. 運行在 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();
        }
    }

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

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

至此,Laravel 就完成了一個 HTTP 請求的請求處理。

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

經(jīng)過一系列漫長的操作,HTTP 請求進入的最終章 - 發(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ā)送報文主題

        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 的請求生命周期的始末。

三 總結(jié)

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

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

所有初始化工作完成后便進入「處理 HTTP 請求」階段。

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

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

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

參考資料

感謝下列優(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)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/28672.html

相關(guān)文章

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

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

    abson 評論0 收藏0
  • Laravel 請求生命周期

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

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

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

    OBKoro1 評論0 收藏0
  • 使用 Swoole 加速 Laravel

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

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

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

    snifes 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<