微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

深度挖掘 Laravel 生命周期

本文首发于个人博客 深度挖掘 Laravel 生命周期,转载请注明出处。

这篇文章我们来聊聊 「Laravel 生命周期」 这个主题。虽然网络上已经有很多关于这个主题的探讨,但这个主题依然值得我们去研究和学习。

我想说的是当我们在决定使用某项技术的时候,除了需要了解它能「做什么」,其实还应当研究它是「怎么做的」。

Laravel 框架或者说任何一个 Web 项目,我们都需要理解它究竟是如何接收到用户发起的 HTTP 请求的;又是如何响应结果给用户的;在处理请求和响应的过程中都存在哪些处理值得深入学习。

所有这些内容其实都包含在 「Laravel 生命周期」 这个主题里面。

本文较长建议使用合适的 IDE 进行代码查阅;或者通过文中的链接,或是代码注释的 「@see」部分直接在 Github 畅读代码

目录结构

  • 摘要
  • 二 生命周期之始末

    • 2.1 加载项目依赖
    • 2.2 创建 Laravel 应用实例

      • 2.2.1 创建应用实例
      • 2.2.2 内核绑定
      • 2.2.3 注册异常处理
      • 2.2.4 小结
    • 2.3 接收请求并响应

      • 2.3.1 解析内核实例
      • 2.3.2 处理 HTTP 请求

        • 2.3.2.1 创建请求实例
        • 2.3.2.2 处理请求

          • 2.3.2.2.1 启动「引导程序」
          • 2.3.2.2.2 发送请求至路由
    • 2.4 发送响应
    • 2.5 终止程序
  • 三 总结
  • 四 生命周期流程图
  • 参考资料

摘要

Laravel 生命周期(或者说请求生命周期)概括起来主要分为 3 个主要阶段:

  • 加载项目依赖
  • 创建 Laravel 应用实例
  • 接收请求并响应

而这 3 个阶段的处理都发生在入口文件 public/index.php 文件内(public/index.PHP一个新安装的 Laravel 项目认入口文件)。

然而 index.PHP 文件仅包含极少的代码,但却出色的完成了一个 HTTP 请求从接收到响应的全部过程,逻辑组织的几近完美。

我们来看下入口文件实现的代码

<?PHP
// 阶段一
require __DIR__.'/../vendor/autoload.PHP';

// 阶段二
$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);

二 生命周期之始末

2.1 加载项目依赖

现代 PHP 依赖于 Composer 包管理器,入口文件通过引入由 Composer 包管理器自动生成的类加载程序,可以轻松注册并加载项目所依赖的第三方组件库。

所有组件的加载工作,仅需一行代码即可完成:

require __DIR__.'/../vendor/autoload.PHP';

2.2 创建 Laravel 应用实例

创建应用实例(或称服务容器),由位于 bootstrap/app.php 文件里的引导程序完成,创建服务容器的过程即为应用初始化的过程,项目初始化时将完成包括注册项目基础服务、注册项目服务提供者别名、注册目录路径等在内的一些列注册工作。

下面是 bootstrap/app.PHP代码,包含两个主要部分「创建应用实例」和「绑定内核至 APP 服务容器」:

<?PHP
// 第一部分: 创建应用实例
$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;

2.2.1 创建应用实例

创建应用实例即实例化 Illuminate\Foundation\Application 这个服务容器,后续我们称其为 APP 容器。在创建 APP 容器主要会完成:注册应用的基础路径并将路径绑定到 APP 容器注册基础服务提供者至 APP 容器注册核心容器别名至 APP 容器 等基础服务的注册工作。

/**
     * 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 内核绑定

接着将关注的焦点转移到绑定内核部分。

Laravel 会依据 HTTP 请求的运行环境的不同,将请求发送至相应的内核: HTTP 内核Console 内核。无论 HTTP 内核还是 Console 内核,它们的作用都是是接收一个 HTTP 请求,随后返回一个响应,就是这么简单。

这篇文章主要研究 HTTP 内核,HTTP 内核继承自 Illuminate\Foundation\Http\Kernel 类.

在 「HTTP 内核」 内它定义了 中间件 相关数组;在 「Illuminate\Foundation\Http\Kernel」 类内部定义了属性名为 「bootstrappers」 的 引导程序 数组。

  • 中间件 提供了一种方便的机制来过滤进入应用的 HTTP 请求。
  • 「引导程序」 包括完成环境检测、配置加载、异常处理、Facades 注册、服务提供者注册、启动服务这六个引导程序。

至于 「中间件」 和 「引导程序」如何被使用的,会在后面的章节讲解。

2.2.3 注册异常处理

项目的异常处理由 App\Exceptions\Handler::class 类完成,这边也不做深入的讲解。

2.2.4 本节小结

通过上面的分析我们可以发现在「创建 Laravel 应用实例」这个阶段它做了很多的基础工作,包括但不限于:创建 APP 容器、注册应用路径、注册基础服务提供者、配置中间件和引导程序等。

2.3 接收请求并响应

在完成创建 APP 容器后即进入了第三个阶段 「接收请求并响应」。

「接收请求并响应」有关代码如下:

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

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

$response->send();

我们需要逐行分析上面的代码,才能窥探其中的原貌。

2.3.1 解析内核实例

在第二阶段我们已经将 HTTP 内核Console 内核 绑定到了 APP 容器,使用时通过 APP 容器make() 方法将内核解析出来,解析的过程就是内核实例化的过程。

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

内核实例化时它的内部究竟又做了哪些操作呢?

进一步挖掘 Illuminate\Foundation\Http\Kernel 内核的 __construct(IlluminateContractsFoundationApplication $app,\Illuminate\Routing\Router $router) 构造方法,它接收 APP 容器路由器 两个参数。

在实例化内核时,构造函数内将在 HTTP 内核定义的「中间件组」注册路由器注册完后就可以在实际处理 HTTP 请求前调用这些「中间件」实现 过滤 请求的目的。

...
    /**
     * Create a new HTTP kernel instance. 创建 HTTP 内核实例
     * 
     * @class Illuminate\Foundation\Http\Kernel
     * @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);
        }
    }
...
...
    /**
     * Register a group of middleware. 注册中间件组
     *
     * @class \Illuminate\Routing\Router
     * @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 \Illuminate\Routing\Router
     * @param  string  $name
     * @param  string  $class
     * @return $this
     */
    public function aliasMiddleware($name,$class)
    {
        $this->middleware[$name] = $class;

        return $this;
    }
...

2.3.2 处理 HTTP 请求

之前的所有处理,基本都是围绕在配置变量、注册服务等运行环境的构建上,构建完成后才是真刀真枪的来处理一个「HTTP 请求」。

处理请求实际包含两个阶段:

  • 创建请求实例
  • 处理请求
// 处理请求
$response = $kernel->handle(
    // 创建请求实例
    $request = Illuminate\Http\Request::capture()
);
2.3.2.1 创建请求实例

请求实例 Illuminate\Http\Requestcapture() 方法内部通过 Symfony 实例创建一个 Laravel 请求实例。这样我们就可以获取用户请求报文的相关信息了。

/**
     * Create a new Illuminate HTTP request from server variables.
     * 
     * @class Illuminate\Http\Request
     * @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  \Symfony\Component\HttpFoundation\Request  $request
     * @return \Illuminate\Http\Request
     */
    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 处理请求

请求处理发生在 HTTP 内核handle() 方法内。

/**
     * Handle an incoming HTTP request.
     *
     * @class Illuminate\Foundation\Http\Kernel
     * @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() 方法接收一个 HTTP 请求,并最终生成一个 HTTP 响应。

继续深入到处理 HTTP 请求的方法 $this->sendRequestThroughRouter($request) 内部。

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

将发现这段代码没有一行废话,它完成了大量的逻辑处理:

  • 首先,将 $request 实例注册APP 容器 供后续使用;
  • 之后,清除之前 $request 实例缓存;
  • 然后,启动「引导程序」;
  • 最后,发送请求至路由。
2.3.2.2.1 启动「引导程序」

记得我们在之前「2.2.2 内核绑定」章节,有介绍在「HTTP 内核」中有把「引导程序(bootstrappers)」绑定到了 APP 容器,以及这些引导程序的具体功能

但是没有聊如何调用这些「引导程序」。

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

        // 启动 「引导程序」
        $this->bootstrap();

        ...
    }

上面的代码块说明在 $this->bootstrap(); 方法内部有实际调用「引导程序」,而 bootstrap() 实际调用的是 APP 容器的 bootstrapWith(),来看看

... 
    /**
     * 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,];

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

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

最终还是要看 Illuminate\Foundation\ApplicationbootstrapWith() 方法究竟如何来启动这些引导程序的。

/**
     * Run the given array of bootstrap classes.
     * 
     * @class  Illuminate\Foundation\Application 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 容器内,会先解析对应的「引导程序」(即实例化),随后调用「引导程序」的 bootstrap() 完成的「引导程序」的启动操作。

作为示例我们随便挑一个「引导程序」来看看其内部的启动原理。

这边我们选 Illuminate\Foundation\Bootstrap\LoadConfiguration::class,它的功能是加载配置文件

还记得我们讲解「2.2 创建 Laravel 应用实例」章节的时候有「注册应用的基础路径并将路径绑定到 APP 容器」。此时,LoadConfiguration 类就是将 config 目录下的所有配置文件读取到一个集合中,这样我们就可以项目里通过 config() 辅助函数获取配置数据。

<?PHP
class LoadConfiguration
{
    /**
     * Bootstrap the given application.
     *
     * @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.PHP
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        $items = [];

        if (file_exists($cached = $app->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  \Illuminate\Contracts\Foundation\Application  $app
     * @param  \Illuminate\Contracts\Config\Repository  $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);
        }
    }

    ...
}

所有 「引导程序」列表功能如下:

2.3.2.2.2 发送请求至路由

完成「引导程序」启动操作后,随机进入到请求处理阶段。

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

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

在 「发送请求至路由」这行代码中,完成了:管道(pipeline)创建、将 $request 传入管道、对 $request 执行「中间件」处理和实际的请求处理四个不同的操作。

在开始前我们需要知道在 Laravel 中有个「中间件」 的概念,即使你还不知道,也没关系,仅需知道它的功能是在处理请求操作之前,对请求进行过滤处理即可,仅当请求符合「中间件」的验证规则时才会继续执行后续处理。

有关 「管道」的相关知识不在本文讲解范围内。

那么,究竟一个请求是如何被处理的呢?

我们来看看 $this->dispatchToRouter() 这句代码,它的方法声明如下:

/**
     * Get the route dispatcher callback. 获取一个路由分发器匿名函数
     *
     * @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 解析内核实例」章节,可知我们已经将 Illuminate\Routing\Router 对象赋值给 $this->router 属性

通过 router 实例的 disptach() 方法去执行 HTTP 请求,在它的内部会完成如下处理:

  1. 查找对应的路由实例
  2. 通过一个实例栈运行给定的路由
  3. 运行在 routes/web.PHP 配置的匹配到的控制器或匿名函数
  4. 返回响应结果
<?PHP

...

//  @see https://github.com/laravel/framework/blob/5.6/src/Illuminate/Routing/Router.PHP
class Router implements RegistrarContract,BindingRegistrar
{    
    /**
     * dispatch the request to the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse
     */
    public function dispatch(Request $request)
    {
        $this->currentRequest = $request;

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

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

    /**
     * Find the route matching a given request. 1. 查找对应的路由实例
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Routing\Route
     */
    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 Events\RouteMatched($route,$request));

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

    /**
     * Run the given route within a Stack "onion" instance. 通过一个实例栈运行给定的路由
     *
     * @param  \Illuminate\Routing\Route  $route
     * @param  \Illuminate\Http\Request  $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. 返回响应结果
        return (new Pipeline($this->container))
                        ->send($request)
                        ->through($middleware)
                        ->then(function ($request) use ($route) {
                            return $this->prepareResponse(
                                // 3. 运行在 routes/web.PHP 配置的匹配到的控制器或匿名函数
                                $request,$route->run()
                            );
                        });
    }

执行 $route->run()方法定义在 Illuminate\Routing\Route 类中,最终执行「在 routes/web.PHP 配置的匹配到的控制器或匿名函数」:

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

这部分如果路由的实现是一个控制器,会完成控制器实例化并执行指定方法;如果是一个匿名函数则直接调用这个匿名函数

其执行结果会通过 Illuminate\Routing\Router::prepareResponse($request,$response)一个响应实例并返回。

至此,Laravel 就完成了一个 HTTP 请求的请求处理。

2.4 发送响应

经过一系列漫长的操作,HTTP 请求进入的最终章 - 发送响应值客户端 $response->send()

<?PHP
// @see https://github.com/laravel/laravel/blob/master/public/index.PHP

// 阶段一
require __DIR__.'/../vendor/autoload.PHP';

// 阶段二
$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);

发送响应由 Illuminate\Http\Response 父类 Symfony\Component\HttpFoundation\Response 中的 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();// 发送响应头部信息
        $this->sendContent();// 发送报文主题

        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 终止程序

程序终止,完成终止中间件的调用
// @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 的请求生命周期的始末。

三 总结

在 「创建 Laravel 应用实例」时不仅会注册项目基础服务、注册项目服务提供者别名、注册目录路径等在内的一系列注册工作;还会绑定 HTTP 内核及 Console 内核到 APP 容器, 同时在 HTTP 内核里配置中间件和引导程序。

进入 「接收请求并响应」里,会依据运行环境从 APP 容器 解析出 HTTP 内核或 Console 内核。如果是 HTTP 内核,还将把「中间件」及「引导程序」注册APP 容器

所有初始化工作完成后便进入「处理 HTTP 请求」阶段。

一个 Http 请求实例会被注册APP 容器,通过启动「引导程序」来设置环境变量、加载配置文件等等系统环境配置;

随后请求被分发到匹配的路由,在路由中执行「中间件」以过滤不满足校验规则的请求,只有通过「中间件」处理的请求才最终处理实际的控制器或匿名函数生成响应结果。

最后发送响应给用户,清理项目中的中间件,完成一个 「请求」 - 「响应」 的生命周期,之后我们的 Web 服务器将等待下一轮用户请求。

参考资料

感谢下列优秀的 Laravel 研究资料:

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐