[原创] Laravel 启动流程
目录
- 1. 程序启动准备
- 2. 请求实例化
-
3. 请求处理
-
3.1 请求处理环境初始化
- 1. 环境监测
\illuminate\foundation\bootstrap\loadenvironmentvariables::class
- 2. 配置加载
\illuminate\foundation\bootstrap\loadconfiguration::class
- 3. 常处理
\illuminate\foundation\bootstrap\handleexceptions::class
- 4. 外观注册
\illuminate\foundation\bootstrap\registerfacades::class
- 5. 服务提供者注册
\illuminate\foundation\bootstrap\registerproviders::class
- 6. 启动提供者
\illuminate\foundation\bootstrap\bootproviders::class
- 1. 环境监测
- 3.2 路由处理请求
- 3.3 处理返回的 response
-
3.1 请求处理环境初始化
- 4. 响应发送和程序终止
laravel 5.5
请求到响应的整个执行阶段归纳为 4 个:
- 程序启动准备阶段
- 文件自动加载
- 服务容器实例化
- 基础服务提供者的注册
- 核心类的实例化
- 请求实例化阶段
- 实例化 request 实例
- 请求处理阶段
- 准备请求处理的环境
- 将请求实例通过中间件处理 及 通过路由和控制器的分发控制
- 响应发送和程序终止阶段
- 将响应内容返回给客户端
- 记录与客户端有关的信息等
1. 程序启动准备
程序入口在 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);
创建服务容器实例
服务容器的创建在 bootstrap\app.php
中进行.
$app = new illuminate\foundation\application( realpath(__dir__.'/../') );
1.1 容器基础配置
容器 application
的构造函数:
public function __construct($basepath = null) { if ($basepath) { $this->setbasepath($basepath); } $this->registerbasebindings(); $this->registerbaseserviceproviders(); $this->registercorecontaineraliases(); }
构造函数 主要完成以下基本配置:
-
目录路径(绑定到容器中, 并提供类方法获取子目录)
public function setbasepath($basepath) { $this->basepath = rtrim($basepath, '\/'); $this->bindpathsincontainer(); return $this; } protected function bindpathsincontainer() { $this->instance('path', $this->path()); $this->instance('path.base', $this->basepath()); $this->instance('path.lang', $this->langpath()); $this->instance('path.config', $this->configpath()); $this->instance('path.public', $this->publicpath()); $this->instance('path.storage', $this->storagepath()); $this->instance('path.database', $this->databasepath()); $this->instance('path.resources', $this->resourcepath()); $this->instance('path.bootstrap', $this->bootstrappath()); }
-
绑定容器自身
protected function registerbasebindings() { static::setinstance($this); $this->instance('app', $this); $this->instance(container::class, $this); $this->instance(packagemanifest::class, new packagemanifest( new filesystem, $this->basepath(), $this->getcachedpackagespath() )); }
-
基础服务注册( event, log, route)
protected function registerbaseserviceproviders() { $this->register(new eventserviceprovider($this)); $this->register(new logserviceprovider($this)); $this->register(new routingserviceprovider($this)); }
-
别名注册
多个接口名 对应一个简短别名, 后续在注册服务时只需绑定到别名上即可 (而不必绑定到具体接口名)
public function registercorecontaineraliases() { foreach ([ 'app' => [\illuminate\foundation\application::class, \illuminate\contracts\container\container::class, \illuminate\contracts\foundation\application::class, \psr\container\containerinterface::class], 'auth' => [\illuminate\auth\authmanager::class, \illuminate\contracts\auth\factory::class], 'auth.driver' => [\illuminate\contracts\auth\guard::class], 'blade.compiler' => [\illuminate\view\compilers\bladecompiler::class], 'cache' => [\illuminate\cache\cachemanager::class, \illuminate\contracts\cache\factory::class], 'cache.store' => [\illuminate\cache\repository::class, \illuminate\contracts\cache\repository::class], 'config' => [\illuminate\config\repository::class, \illuminate\contracts\config\repository::class], 'cookie' => [\illuminate\cookie\cookiejar::class, \illuminate\contracts\cookie\factory::class, \illuminate\contracts\cookie\queueingfactory::class], 'encrypter' => [\illuminate\encryption\encrypter::class, \illuminate\contracts\encryption\encrypter::class], 'db' => [\illuminate\database\databasemanager::class], 'db.connection' => [\illuminate\database\connection::class, \illuminate\database\connectioninterface::class], 'events' => [\illuminate\events\dispatcher::class, \illuminate\contracts\events\dispatcher::class], 'files' => [\illuminate\filesystem\filesystem::class], 'filesystem' => [\illuminate\filesystem\filesystemmanager::class, \illuminate\contracts\filesystem\factory::class], 'filesystem.disk' => [\illuminate\contracts\filesystem\filesystem::class], 'filesystem.cloud' => [\illuminate\contracts\filesystem\cloud::class], 'hash' => [\illuminate\contracts\hashing\hasher::class], 'translator' => [\illuminate\translation\translator::class, \illuminate\contracts\translation\translator::class], 'log' => [\illuminate\log\writer::class, \illuminate\contracts\logging\log::class, \psr\log\loggerinterface::class], 'mailer' => [\illuminate\mail\mailer::class, \illuminate\contracts\mail\mailer::class, \illuminate\contracts\mail\mailqueue::class], 'auth.password' => [\illuminate\auth\passwords\passwordbrokermanager::class, \illuminate\contracts\auth\passwordbrokerfactory::class], 'auth.password.broker' => [\illuminate\auth\passwords\passwordbroker::class, \illuminate\contracts\auth\passwordbroker::class], 'queue' => [\illuminate\queue\queuemanager::class, \illuminate\contracts\queue\factory::class, \illuminate\contracts\queue\monitor::class], 'queue.connection' => [\illuminate\contracts\queue\queue::class], 'queue.failer' => [\illuminate\queue\failed\failedjobproviderinterface::class], 'redirect' => [\illuminate\routing\redirector::class], 'redis' => [\illuminate\redis\redismanager::class, \illuminate\contracts\redis\factory::class], 'request' => [\illuminate\http\request::class, \symfony\component\httpfoundation\request::class], 'router' => [\illuminate\routing\router::class, \illuminate\contracts\routing\registrar::class, \illuminate\contracts\routing\bindingregistrar::class], 'session' => [\illuminate\session\sessionmanager::class], 'session.store' => [\illuminate\session\store::class, \illuminate\contracts\session\session::class], 'url' => [\illuminate\routing\urlgenerator::class, \illuminate\contracts\routing\urlgenerator::class], 'validator' => [\illuminate\validation\factory::class, \illuminate\contracts\validation\factory::class], 'view' => [\illuminate\view\factory::class, \illuminate\contracts\view\factory::class], ] as $key => $aliases) { foreach ($aliases as $alias) { $this->alias($key, $alias); } } }
1.2 核心类绑定
$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 核心类
- 命令行 核心类
- 异常处理类
1.3 实例化 http 核心类
$kernel = $app->make(illuminate\contracts\http\kernel::class);
http 核心类的构造函数
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); } }
上述过程主要做的事是将中间件赋值给路由
- 中间件顺序优先级列表
- 中间件组
- 中间件别名
核心类 app/http/kernel.php
<?php namespace app\http; use illuminate\foundation\http\kernel as httpkernel; class kernel extends httpkernel { // 全局中间件,最先调用 protected $middleware = [ // 检测是否应用是否进入『维护模式』 // 见:https://d.laravel-china.org/docs/5.5/configuration#maintenance-mode \illuminate\foundation\http\middleware\checkformaintenancemode::class, // 检测请求的数据是否过大 \illuminate\foundation\http\middleware\validatepostsize::class, // 对提交的请求参数进行 php 函数 `trim()` 处理 \app\http\middleware\trimstrings::class, // 将提交请求参数中空子串转换为 null \illuminate\foundation\http\middleware\convertemptystringstonull::class, // 修正代理服务器后的服务器参数 \app\http\middleware\trustproxies::class, ]; // 定义中间件组 protected $middlewaregroups = [ // web 中间件组,应用于 routes/web.php 路由文件 'web' => [ // cookie 加密解密 \app\http\middleware\encryptcookies::class, // 将 cookie 添加到响应中 \illuminate\cookie\middleware\addqueuedcookiestoresponse::class, // 开启会话 \illuminate\session\middleware\startsession::class, // 认证用户,此中间件以后 auth 类才能生效 // 见:https://d.laravel-china.org/docs/5.5/authentication \illuminate\session\middleware\authenticatesession::class, // 将系统的错误数据注入到视图变量 $errors 中 \illuminate\view\middleware\shareerrorsfromsession::class, // 检验 csrf ,防止跨站请求伪造的安全威胁 // 见:https://d.laravel-china.org/docs/5.5/csrf \app\http\middleware\verifycsrftoken::class, // 处理路由绑定 // 见:https://d.laravel-china.org/docs/5.5/routing#route-model-binding \illuminate\routing\middleware\substitutebindings::class, ], // api 中间件组,应用于 routes/api.php 路由文件 'api' => [ // 使用别名来调用中间件 // 请见:https://d.laravel-china.org/docs/5.5/middleware#为路由分配中间件 'throttle:60,1', 'bindings', ], ]; // 中间件别名设置,允许你使用别名调用中间件,例如上面的 api 中间件组调用 protected $routemiddleware = [ // 只有登录用户才能访问,我们在控制器的构造方法中大量使用 'auth' => \illuminate\auth\middleware\authenticate::class, // http basic auth 认证 'auth.basic' => \illuminate\auth\middleware\authenticatewithbasicauth::class, // 处理路由绑定 // 见:https://d.laravel-china.org/docs/5.5/routing#route-model-binding 'bindings' => \illuminate\routing\middleware\substitutebindings::class, // 用户授权功能 'can' => \illuminate\auth\middleware\authorize::class, // 只有游客才能访问,在 register 和 login 请求中使用,只有未登录用户才能访问这些页面 'guest' => \app\http\middleware\redirectifauthenticated::class, // 访问节流,类似于 『1 分钟只能请求 10 次』的需求,一般在 api 中使用 'throttle' => \illuminate\routing\middleware\throttlerequests::class, ]; }
2. 请求实例化
以处理 http 请求为例
index.php
入口文件
$response = $kernel->handle( $request = illuminate\http\request::capture() );
请求是通过 illuminate\http\request::capture()
实例化的, 主要是将请求信息以对象形式表现出来
3. 请求处理
入口文件:
$response = $kernel->handle( $request = illuminate\http\request::capture() );
$kernel->handle(...)
处理请求过程
illuminate\foundation\http\kernel
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; } 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()); } protected function dispatchtorouter() { return function ($request) { $this->app->instance('request', $request); return $this->router->dispatch($request); }; }
实际处理请求逻辑主要在 sendrequestthroughrouter
方法中, 它主要做了:
核心类的初始化
-
经由中间件过滤后将请求最终交由
router
处理对于 http 请求处理, 中间件包括:
protected $middleware = [ \illuminate\foundation\http\middleware\checkformaintenancemode::class, \illuminate\foundation\http\middleware\validatepostsize::class, \app\http\middleware\trimstrings::class, \illuminate\foundation\http\middleware\convertemptystringstonull::class, \app\http\middleware\trustproxies::class, ];
该中间件数组定义在 http 核心类中, 同时在核心类的构造函数中传递给
router
类
3.1 请求处理环境初始化
核心类的初始化 bootstrap()
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; }
在服务容器 application
类中
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]); } }
该步骤主要是主要是对核心类中定义的 $bootstrappers
数组元素(引导类)初始化.
bootstrap 过程具体是在服务容器来中进行, 由核心类调用并传入待初始化的类
http 核心类默认包含以下 6 个启动服务:
1. 环境监测 \illuminate\foundation\bootstrap\loadenvironmentvariables::class
从 .env
文件中解析环境变量到 getevn()
, $_env
, $_server
依赖
vlucas/phpdotenv
扩展包
2. 配置加载 \illuminate\foundation\bootstrap\loadconfiguration::class
载入 config
目录下所有 php 配置文件, 并将生成的配置存储类绑定到服务容器 $app['config']
同时配置时区及 多字节格式(utf8)
3. 常处理 \illuminate\foundation\bootstrap\handleexceptions::class
报告所有错误 error_report(e_all)
提供对未捕获的异常, 错误的全局处理 set_error_handler
, set_exception_handler
, register_shutdown_function
4. 外观注册 \illuminate\foundation\bootstrap\registerfacades::class
从 app.aliases
中读取外观配置数组
'aliases' => [ 'app' => illuminate\support\facades\app::class, 'artisan' => illuminate\support\facades\artisan::class, 'auth' => illuminate\support\facades\auth::class, 'blade' => illuminate\support\facades\blade::class, 'broadcast' => illuminate\support\facades\broadcast::class, 'bus' => illuminate\support\facades\bus::class, 'cache' => illuminate\support\facades\cache::class, 'config' => illuminate\support\facades\config::class, 'cookie' => illuminate\support\facades\cookie::class, 'crypt' => illuminate\support\facades\crypt::class, 'db' => illuminate\support\facades\db::class, 'eloquent' => illuminate\database\eloquent\model::class, 'event' => illuminate\support\facades\event::class, 'file' => illuminate\support\facades\file::class, 'gate' => illuminate\support\facades\gate::class, 'hash' => illuminate\support\facades\hash::class, 'lang' => illuminate\support\facades\lang::class, 'log' => illuminate\support\facades\log::class, 'mail' => illuminate\support\facades\mail::class, 'notification' => illuminate\support\facades\notification::class, 'password' => illuminate\support\facades\password::class, 'queue' => illuminate\support\facades\queue::class, 'redirect' => illuminate\support\facades\redirect::class, 'redis' => illuminate\support\facades\redis::class, 'request' => illuminate\support\facades\request::class, 'response' => illuminate\support\facades\response::class, 'route' => illuminate\support\facades\route::class, 'schema' => illuminate\support\facades\schema::class, 'session' => illuminate\support\facades\session::class, 'storage' => illuminate\support\facades\storage::class, 'url' => illuminate\support\facades\url::class, 'validator' => illuminate\support\facades\validator::class, 'view' => illuminate\support\facades\view::class, ],
使用 spl_autoload_register(...)
处理类加载, 配合 class_alias()
提供类的别名调用
facade外观类基类依赖
__callstatic` 调用方法( 使用服务容器实例化对应类)
5. 服务提供者注册 \illuminate\foundation\bootstrap\registerproviders::class
从 app.providers
中读取所有服务提供者
'providers' => [ /* * laravel framework service providers... */ illuminate\auth\authserviceprovider::class, illuminate\broadcasting\broadcastserviceprovider::class, illuminate\bus\busserviceprovider::class, illuminate\cache\cacheserviceprovider::class, illuminate\foundation\providers\consolesupportserviceprovider::class, illuminate\cookie\cookieserviceprovider::class, illuminate\database\databaseserviceprovider::class, illuminate\encryption\encryptionserviceprovider::class, illuminate\filesystem\filesystemserviceprovider::class, illuminate\foundation\providers\foundationserviceprovider::class, illuminate\hashing\hashserviceprovider::class, illuminate\mail\mailserviceprovider::class, illuminate\notifications\notificationserviceprovider::class, illuminate\pagination\paginationserviceprovider::class, illuminate\pipeline\pipelineserviceprovider::class, illuminate\queue\queueserviceprovider::class, illuminate\redis\redisserviceprovider::class, illuminate\auth\passwords\passwordresetserviceprovider::class, illuminate\session\sessionserviceprovider::class, illuminate\translation\translationserviceprovider::class, illuminate\validation\validationserviceprovider::class, illuminate\view\viewserviceprovider::class, /* * package service providers... */ /* * application service providers... */ app\providers\appserviceprovider::class, app\providers\authserviceprovider::class, // app\providers\broadcastserviceprovider::class, app\providers\eventserviceprovider::class, app\providers\routeserviceprovider::class, # 路由表生成 ],
服务提供者经过解析后分为 3 种类型的服务提供者:
-
eager 类型
马上调用
register
注册 -
deferred 类型
记录下来, 当服务容器解析对应服务时, 才注册对应的服务提供者
-
when 类型
记录下来, 当对应 event 触发时在注册对应服务提供者
6. 启动提供者 \illuminate\foundation\bootstrap\bootproviders::class
调用服务容器的 boot()
方法, 依次调用在服务容器中 register
的所有服务提供者的 boot()
方法
3.2 路由处理请求
在内核处理请求, 将请求实例通过中间件处理后, 将请求的处理交给路由 router 进行控制器的分发.
http kernel
protected function dispatchtorouter() { return function ($request) { $this->app->instance('request', $request); return $this->router->dispatch($request); }; }
路由表存储结构说明
illuminate\routing\route
存储单条路由
illuminate\routing\routecollection
保存所有route
实例, 形成路由表
illuminate\routing\router
类实例持有routecollection
路由表实例.即, 一个
router
持有一个routecollection
, 而routecollection
拥有 n 个route
在 router
中对请求的处理同样经过一系列的 路由中间件
# 路由处理请求的入库 public function dispatchtoroute(request $request) { return $this->runroute($request, $this->findroute($request)); } # 根据请求的 url 和 method 查找对应的 route protected function findroute($request) { $this->current = $route = $this->routes->match($request); $this->container->instance(route::class, $route); return $route; } # 根据对应的请求和路由条目, 返回相应的 $response 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) ); } # 请求经过路由中间件过滤后, 交由 route 的 run() 方法处理 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\controllerdispatcher::dispatch
处理
public function dispatch(route $route, $controller, $method) { $parameters = $this->resolveclassmethoddependencies( $route->parameterswithoutnulls(), $controller, $method ); if (method_exists($controller, 'callaction')) { return $controller->callaction($method, $parameters); } return $controller->{$method}(...array_values($parameters)); }
剩下的事情就是 controller控制器 的事了.
3.3 处理返回的 response
在 router
中有一个方法, 用于对返回的 $response
进行处理
public function prepareresponse($request, $response) { return static::toresponse($request, $response); } /** * @return \illuminate\http\response|\illuminate\http\jsonresponse */ public static function toresponse($request, $response) { if ($response instanceof responsable) { $response = $response->toresponse($request); } if ($response instanceof psrresponseinterface) { $response = (new httpfoundationfactory)->createresponse($response); } elseif (! $response instanceof symfonyresponse && ($response instanceof arrayable || $response instanceof jsonable || $response instanceof arrayobject || $response instanceof jsonserializable || is_array($response))) { $response = new jsonresponse($response); } elseif (! $response instanceof symfonyresponse) { $response = new response($response); } if ($response->getstatuscode() === response::http_not_modified) { $response->setnotmodified(); } return $response->prepare($request); # 最后的处理 }
上述过程中, 在返回 $response
之前进行了最后的处理 $response->prepare($request)
该过程是在 symfony\component\httpfoundation\response::prepare()
中进行
对响应的封装是通过
illuminate\http\response
类完成, 该类底层是 symfony 框架的 response 类即,
symfony\component\httpfoundation\response
public function prepare(request $request) { $headers = $this->headers; if ($this->isinformational() || $this->isempty()) { $this->setcontent(null); $headers->remove('content-type'); $headers->remove('content-length'); } else { // content-type based on the request if (!$headers->has('content-type')) { $format = $request->getrequestformat(); if (null !== $format && $mimetype = $request->getmimetype($format)) { $headers->set('content-type', $mimetype); } } // fix content-type $charset = $this->charset ?: 'utf-8'; if (!$headers->has('content-type')) { $headers->set('content-type', 'text/html; charset='.$charset); } elseif (0 === stripos($headers->get('content-type'), 'text/') && false === stripos($headers->get('content-type'), 'charset')) { // add the charset $headers->set('content-type', $headers->get('content-type').'; charset='.$charset); } // fix content-length if ($headers->has('transfer-encoding')) { $headers->remove('content-length'); } if ($request->ismethod('head')) { // cf. rfc2616 14.13 $length = $headers->get('content-length'); $this->setcontent(null); if ($length) { $headers->set('content-length', $length); } } } // fix protocol if ('http/1.0' != $request->server->get('server_protocol')) { $this->setprotocolversion('1.1'); } // check if we need to send extra expire info headers if ('1.0' == $this->getprotocolversion() && false !== strpos($this->headers->get('cache-control'), 'no-cache')) { $this->headers->set('pragma', 'no-cache'); $this->headers->set('expires', -1); } $this->ensureieoversslcompatibility($request); return $this; }
4. 响应发送和程序终止
4.1 响应的发送
在 index.php
入口文件的最后是将响应返回给客户端
$response->send();
symfony\component\httpfoundation\response
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; } public function sendheaders() { // headers have already been sent by the developer if (headers_sent()) { return $this; } // headers foreach ($this->headers->allpreservecase() as $name => $values) { foreach ($values as $value) { header($name.': '.$value, false, $this->statuscode); } } // status header(sprintf('http/%s %s %s', $this->version, $this->statuscode, $this->statustext), true, $this->statuscode); return $this; } public function sendcontent() { echo $this->content; return $this; }
4.2 请求中止
在 index.php
入口文件的最后:
$kernel->terminate($request, $response);
依旧以 http kernel 为例:
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) = $this->parsemiddleware($middleware); $instance = $this->app->make($name); if (method_exists($instance, 'terminate')) { $instance->terminate($request, $response); } } }
此处的中间件指的是定义在 kernel 中的 $middleware
中间件数组列表, 不包含 路由中间件.
laravel 5.1 注: 默认只有会话中间件包含
terminate()
函数
application
服务容器的中止处理函数
public function terminate() { foreach ($this->terminatingcallbacks as $terminating) { $this->call($terminating); } }