虽然关于 laravel 的生命周期的文章已经很多了,但是也很有必要根据自己的理解分享出一篇文章来,加深下印象。
简介
Laravel的生命周期开始于 public/index.php,结束于 public/index.php。客户端的所有请求都经由Web服务器引导到这个文件中。以下是public/index.php 文件的源码和注释:
#public/index.php 文件 // 定义了laravel一个请求的开始时间 define('LARAVEL_START', microtime(true)); // composer自动加载机制,加载项目依赖 require __DIR__.'/../vendor/autoload.php'; // 这句话你就可以理解laravel,在最开始引入了一个ioc容器。 $app = require_once __DIR__.'/../bootstrap/app.php'; // 这个相当于我们创建了Kernel::class的服务提供者 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); // 获取一个 Request ,返回一个 Response。以把该内核想象作一个代表整个应用的大黑盒子,输入 HTTP 请求,返回 HTTP 响应 // 处理请求 $response = $kernel->handle( // 创建请求实例 $request = Illuminate\Http\Request::capture() ); // 发送响应,就是把我们服务器的结果返回给浏览器。 $response->send(); // 终止程序,这个就是执行我们比较耗时的请求, $kernel->terminate($request, $response);
由上可知 Laravel 的生命周期分为以下3个主要阶段:
•加载项目依赖。
•创建Laravel应用实例
•接收请求并响应。
接下来我们根据 public/index.php 文件,开始 Laravel 的生命周期之旅吧!
一、Composer 自动加载项目依赖
// composer自动加载机制 require __DIR__.'/../vendor/autoload.php';
Composer 是 PHP 的包管理器,用来管理项目依赖的工具,autoload.php 中引入了 Composer 自动生成的加载程序,实现加载第三方依赖。
autoload.php 文件代码:
// autoload.php @generated by Composer require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInit101671ca9bbc2f62f8335eb842637291::getLoader();
二、创建应用实例
$app = require_once __DIR__.'/../bootstrap/app.php';
bootstrap/app.php 文件代码:
// 创建Laravel应用的ioc容器, $app = new Illuminate\Foundation\Application( $_ENV['APP_BASE_PATH'] ?? dirname(__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;
如果你理解了 Ioc(控制反转),那么对于以上代码你一定很熟悉。
Ioc 容器(服务容器) 是 Laravel 的核心,这一阶段主要实现了 2大功能:
1、创建容器
2、绑定内核
创建容器
$app = new Illuminate\Foundation\Application( $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__) );
我们进入 Illuminate\Foundation\Application 容器中,以下是构造函数的分析:
/** * Create a new Illuminate application instance. * * @param string|null $basePath * @return void */ public function __construct($basePath = null) { if ($basePath) { // 1、路径绑定 $this->setBasePath($basePath); } // 2、基础绑定 $this->registerBaseBindings(); // 3、基础服务提供者绑定(事件,日志,路由) $this->registerBaseServiceProviders(); // 4、核心别名绑定,目的是给核心的类命名空间设置别名,以便后续使用 $this->registerCoreContainerAliases(); }
绑定内核
// 完成内核的绑定 // HTTP内核 $app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class ); // Console内核 $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 来启动框架的,都会用到 Http Kernel(主要作用就是接受请求并返回响应),而其他的例如通过 artisan 命令、计划任务、队列等启动框架进行处理的都会用到 Console 内核。
其中 HTTP 内核类继承 Illuminate\Foundation\Http\Kernel ,HTTP内核类中定义了中间件相关数组,中间件主要是提供了一种方便机制用来过滤进入应用的请求和处理HTTP响应。
HTTP 内核类:
<?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内核类的父类:Illuminate\Foundation\Http\Kernel 提供了名为 $bootstrappers 的引导程序数组,包括了环境检测、加载配置、处理异常、Facades注册、服务提供者注册、启动服务这6个 程序。
/** * 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 内核:
一个健壮的应用程序除了满足网络请求外,还应该包括执行计划任务、异步队列等,Laravel中通过artisan工具定义各种命令来完成非 HTTP 请求的各种场景。artisan命令通过 Laravel 的 Console 内核完成对应用核心组件的调度来完成任务。Console 内核在这不做详细介绍。
绑定异常处理
异常处理由 App\Exceptions\Handler 类完成,所有的异常处理都由其处理,在这里同样不做详细介绍。
三、接收请求并响应
解析内核
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
这里将 HTTP 内核解析出来,我们进一步查看Illuminate\Contracts\Http\Kernel::class 的内部代码,
构造函数中注入了app容器和路由器2个函数,在实例化内核的过程中,将内核中定义的中间件注册到路由器中,注册完成后便可以处理HTTP请求前调用中间件 实现过滤请求的目的。
Illuminate\Foundation\Http\Kernel 的构造函数:
/** * 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 请求
// handle 方法处理请求 $response = $kernel->handle( // 创建请求实例 $request = Illuminate\Http\Request::capture() );
创建请求实例:在处理请求过程之前会通过 Illuminate\Http\Request 的 capture 方法,以进入应用的HTTP请求信息为基础,创建出一个 Laravel Request请求实例,在后续应用剩余的生命周期中Request请求实例就是对本次HTTP请求的抽象。
/** * 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 处理请求:将 HTTP 请求抽象成 Laravel Request 请求实例后,请求实例会被传导进入到HTTP内核的 handle 方法内部,请求的处理就是由 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 方法接收了一个请求,并在最后返回了一个 HTTP响应。
接下来进入 sendRequestThroughRouter 方法,通过中间件/路由器发送给定的请求。
该方法的程序执行如下:
1、将 request 请求实例注册到 app 容器当中
2、清除之前的 request 实例缓存
3、启动引导程序:加载内核中定义的引导程序来引导启动应用
4、将请求发送到路由:通过 Pipeline 对象传输 HTTP请求对象流经框架中定义的HTTP中间件和路由器来完成过滤请求,最终将请求传递给处理程序(控制器方法或者路由中的闭包)由处理程序返回相应的响应。
/** * 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 引导程序
/** * 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, ]; /*引导启动Laravel应用程序 1. DetectEnvironment 检查环境 2. LoadConfiguration 加载应用配置 3. ConfigureLogging 配置日至 4. HandleException 注册异常处理的Handler 5. RegisterFacades 注册Facades 6. RegisterProviders 注册Providers 7. BootProviders 启动Providers */
关于引导程序的启动原理,有时间我们再抽出来看看。
发送响应
$response->send();
经过了以上阶段,终于获取到了我们想要的数据,接下来是将数据响应到客户端。
程序由在 Illuminate\Http\Response 内部由其父类 Symfony\Component\HttpFoundation\Response 的 send() 方法实现。
/** * Sends HTTP headers and content. * * @return $this */ public function send() { $this->sendHeaders(); // 发送头部信息 $this->sendContent(); // 发送报文主题 if (\function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { static::closeOutputBuffers(0, true); } return $this; }
四、终止应用程序
该过程调用终止中间件。
响应完成后,HTTP 内核会调用 terminate 中间件做一些后续的处理工作。比如,Laravel 内置的 session 中间件会在响应发送到浏览器之后将会话数据写入存储器中。
HTTP 内核的 terminate 方法会调用 terminate 中间件的 terminate 方法,调用完成后,整个生命周期结束。
$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); } } }
五、总结
在Laravel 的整个生命周期中,加载项目依赖、创建应用实例、接收并响应请求,终止程序,内核都起到了串联作用。
首先,创建 Laravel 应用程序 阶段时,包含了注册项目基础服务、注册项目服务提供者别名、注册目录路径、异常类绑定等工作,同时在HTTP 内核中配置了引导程序。接着,在 接收请求并响应 阶段时,会根据运行的环境解析出 HTTP 内核或 Console 内核。在 HTTP 内核中把中间件注册到路由器中。然后,处理请求阶段的过程中,将请求的实例注册到app容器中,通过引导程序启动应用,最后发送请求到路由。之后,通过Response类响应数据。最后,通过terminate 方法终止程序。
以上就是关于 Laravel 生命周期的详细解析。想要获取更多laravel教程欢迎关注编程学习网
扫码二维码 获取免费视频学习资料
- 本文固定链接: http://phpxs.com/post/8394/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料