Laravel 的生命周期主要分为四个阶段:
- 加载依赖
- 创建应用实例
- 接收请求并响应
- 请求结束进行回调
这四个阶段都在 index.php 中完成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php // 加载依赖 require __DIR__.'/../vendor/autoload.php';
// 创建应用实例 $app = require_once __DIR__.'/../bootstrap/app.php';
// 实例化 HTTP 内核 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
// 接收请求,生成响应 $response = $kernel->handle( $request = Illuminate\Http\Request::capture() );
// 发送响应 $response->send();
// 请求结束,进行回调 $kernel->terminate($request, $response);
|
1. 加载依赖
laravel 框架依赖 composer 管理扩展包,通过引入 composer 的自动加载程序,就可以轻松完成扩展加载:
1
| require __DIR__.'/../vendor/autoload.php';
|
2 创建应用实例
这一步主要由以下几个小步骤组成:
创建应用实例,由 bootstrap/app.php 完成,然后注册三个核心。
1 2 3 4 5 6 7
| <?php // 第一部分: 创建应用实例 $app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') );
……
|
2.1 完成基础注册
应用实例创建后,再来看一下具体是怎么工作的,打开 Illuminate\Foundation\Application
,其代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public function __construct($basePath = null) { // 应用的路径绑定 if ($basePath) { $this->setBasePath($basePath); }
// 将基础绑定注册到容器中,容器名 $this->registerBaseBindings(); // 将基础服务提供者注册到容器 Event、Log、Route $this->registerBaseServiceProviders(); // 将核心类别名注册到容器 $this->registerCoreContainerAliases(); }
|
2.2 内核绑定
接着看 bootstrap/app.php
中的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ……
// 第二步,内核绑定
$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 );
|
绑定三个内核,HTTP、Console、Exception内核。
3 接收请求并响应
再次回到 index.php,查看请求和响应的相关代码:
1 2 3 4 5 6 7 8 9 10 11
| ……
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle( $request = Illuminate\Http\Request::capture() );
$response->send();
……
|
这一步也是由几个小步骤组成:
3.1 注册中间件到路由
在 Illuminate\Contracts\Http\Kernel::class
类的构造方法中,将在 HTTP 内核定义的「中间件」注册到路由,注册完后就可以在实际处理 HTTP 请求前调用这些「中间件」实现过滤请求的目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| protected $middlewarePriority = [ \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class, \Illuminate\Routing\Middleware\ThrottleRequests::class, \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Auth\Middleware\Authorize::class, ];
public function __construct(Application $app, Router $router) { $this->app = $app; $this->router = $router;
$this->syncMiddlewareToRouter(); }
// 注册中间件到路由 protected function syncMiddlewareToRouter() { $this->router->middlewarePriority = $this->middlewarePriority;
foreach ($this->middlewareGroups as $key => $middleware) { $this->router->middlewareGroup($key, $middleware); }
foreach ($this->routeMiddleware as $key => $middleware) { $this->router->aliasMiddleware($key, $middleware); } }
|
3.2 处理请求
处理请求实际包含两个阶段:
3.2.1 创建请求实例
通过 Symfony 实例创建一个 Laravel 请求实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public static function capture() { static::enableHttpMethodParameterOverride();
return static::createFromBase(SymfonyRequest::createFromGlobals()); }
public static function createFromBase(SymfonyRequest $request) { $newRequest = (new static)->duplicate( $request->query->all(), $request->request->all(), $request->attributes->all(), $request->cookies->all(), $request->files->all(), $request->server->all() );
$newRequest->headers->replace($request->headers->all());
$newRequest->content = $request->content;
$newRequest->request = $newRequest->getInputSource();
return $newRequest; }
|
3.2.2 处理请求
在 HTTP 核心的 handdle 方法内,接收一个请求,也就是上一步创建的请求实例,最终生成一个响应。
主要步驟如下:
- 注册请求到容器
- 运行引导程序
- 环境检测,将 env 中的配置读取到变量中
- 配置文件加载
- 加载异常处理
- 注册门面
- 注册服务提供者
- 服务启动
- 发送请求到路由
- 返回响应
HTTP 核心的 handle 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public function handle($request) { try { $request->enableHttpMethodParameterOverride();
$response = $this->sendRequestThroughRouter($request); } catch (Throwable $e) { $this->reportException($e);
$response = $this->renderException($request, $e); }
$this->app['events']->dispatch( new RequestHandled($request, $response) );
return $response; }
|
再往下深入,查看 $response = $this->sendRequestThroughRouter($request);
的具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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 注册到容器内,然后清除掉之前的 request 实例缓存,启动引导程序,然后将请求发送到路由。
接下来,看一下引导程序是做什么的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 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, ];
public function bootstrap() { if (! $this->app->hasBeenBootstrapped()) { $this->app->bootstrapWith($this->bootstrappers()); } }
protected function bootstrappers() { return $this->bootstrappers; }
// src/Illuminate/Foundation/Application.php public function bootstrapWith(array $bootstrappers) { $this->hasBeenBootstrapped = true;
foreach ($bootstrappers as $bootstrapper) { $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);
$this->make($bootstrapper)->bootstrap($this);
$this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]); } }
|
在容器内的具体实现方法中,会先解析引导程序,然后再通过调用引导程序的 bootstrap
方法来启动服务。
引导程序功能:
- 环境检测,将 env 配置文件载入到
$_ENV
变量中
- 加载配置文件
- 加载异常处理
- 加载 Facades,注册完成后可以用别名的方式访问具体的类
- 注册服务提供者,在这里我们会将配置在 app.php 文件夹下 providers 节点的服务器提供者注册到 APP 容器,供请求处理阶段使用
- 服务启动
在发送请求至路由这行代码中,完成了:管道(pipeline)创建、将 request 传入管道、对 request 执行中间件处理和实际的请求处理四个不同的操作。
1 2 3 4
| return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter());
|
继续深入 $this->dispatchToRouter()
,分析程序是如何处理请求的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| protected function dispatchToRouter() { return function ($request) { // 将请求注册到容器 $this->app->instance('request', $request);
return $this->router->dispatch($request); }; }
public function dispatch(Request $request) { $this->currentRequest = $request;
return $this->dispatchToRoute($request); }
public function dispatchToRoute(Request $request) { return $this->runRoute($request, $this->findRoute($request)); }
// 查找路由 protected function findRoute($request) { $this->current = $route = $this->routes->match($request);
$this->container->instance(Route::class, $route);
return $route; }
protected function runRoute(Request $request, Route $route) { $request->setRouteResolver(function () use ($route) { return $route; });
$this->events->dispatch(new RouteMatched($route, $request));
return $this->prepareResponse($request, $this->runRouteWithinStack($route, $request) ); }
protected function runRouteWithinStack(Route $route, Request $request) { $shouldSkipMiddleware = $this->container->bound('middleware.disable') && $this->container->make('middleware.disable') === true;
$middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);
// 返回运行结果 return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { // 运行匹配到的路由控制器或匿名函数 return $this->prepareResponse( $request, $route->run() ); }); }
|
执行 $route->run()
的方法定义在 Illuminate\Routing\Route
类中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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(); } }
|
如果路由的实现是一个控制器,会完成控制器实例化并执行指定方法;如果是一个匿名函数就会直接调用。最终响应通过 prepareResponse
返回。
3.2.3 发送响应
绕了一大圈,最后终于回到了开始的地方
1 2
| // 发送响应 $response->send();
|
最终发送,由 src/Illuminate/Http/Response.php
的父类 Symfony\Component\HttpFoundation\Response
完成:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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; }
|
4 请求结束,进行回调
1
| $kernel->terminate($request, $response);
|
继续往下看,核心的 terminate
方法:
1 2 3 4 5 6
| public function terminate($request, $response) { $this->terminateMiddleware($request, $response);
$this->app->terminate(); }
|
terminateMiddleware
中,进行终止中间件,$this->app->terminate()
终止程序。
总结
创建应用实例,完成项目路径注册、基础服务注册、核心类别名注册,然后将 HTTP 和 Console, Exception 核心注册到容器。
然后再实例化内核,将中间件加载到路由,再将请求注册到容器,然后运行引导程序,进行环境检测、加载系统配置等系统环境配置。
然后进行中间件校验,通过校验后才会最终处理实际的控制器或匿名函数并生成响应。
最终,发送响应给用户,清理项目中的中间件,完成一个请求周期。