<?php
//laravel 5.1.40 (LTS)
//注册自动加载->初始化容器->注册基础事件、路由->注册http内核、console内核、异常处理内核->生成$request对象->http内核初始化->将$request副本扔给http内核处理(中间件处理、路由分发处理、结合用户自定义逻辑等)->处理完成生成一个$response->输出$response的相应信息->内核做一些中止操作
//入口文件->载入bootstrap下的autolad.php->载入vendor下的autoload.php
//载入composer下的autoload_real.php实现composer的自动加载
//composer自动加载流程简介
//php版本>=5.6会调用autoload_static.php中的getInitializer方法(传入\Composer\Autoload\ClassLoader实例)
//该方法返回一个匿名函数,然后在autoload_real.php中通过call_user_func调用它
//将autoload_static.php中的配置字段设置到\Composer\Autoload\ClassLoader的字段中
//然后auto_real.php继续往下走,调用\Composer\Autoload\ClassLoader的register方法
//该方法中通过spl_autoload_register来注册\Composer\Autoload\ClassLoader::loadClass方法实现自动加载
//继续走下去将autoload_static.php中的配置files全部加载进来(这里是直接加载,没有使用动态自动加载)
//此时,加载核心文件和注册自动加载已经走完
//入口文件继续执行,加载/bootstrap/app.php->实例化laravel框架Applation(它继承laravel的Container容器)
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
//构造函数中,做了如下几件事
//注册基础绑定,将Illuminate\Foundation\Application实例赋值给容器的静态字段$instance
//同时将放入容器的instances字段数组,有2个key可以定位到它 'app' 和 'Illuminate\Container\Container'
$this->registerBaseBindings();
//注册基础服务供应,事件服务供应和路由服务供应(两者都最终继承于Illuminate\Support\ServiceProvider)
//注册过程中会实例化事件服务和路由服务实例,并将当前Application实例注入到它们的父类ServiceProvider的app字段
$this->registerBaseServiceProviders();
/******Application->registerBaseServiceProviders(EventServiceProvider实例) BEGIN******/
//注册事件过程简单分析,以EventServiceProvider为例
//Application.php中调用register方法,直接传入EventServiceProvider实例,同时会把Application对象注入到EventServiceProvider中
$this->register(new EventServiceProvider($this));
//register方法中首先会调用获取供应方法,此方法返回NULL,所以$registered=NULL
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
//getProvider方法会调用Illuminate\Support\Arr::first方法,由于此时Application的serviceProviders为空数组
//所以first方法中会直接调用value函数,返回NULL。value函数在composer的$files中载入/laravel/framework/src/Illuminate/Support/helpers.php
return value($default);
//继续走下去,会调用Illuminate\Support\ServiceProvider自己的register方法
//此方法会调用之前注入的Application的父类Container的singleton方法(翻译为:独生子女,表示单例)
//然后会调用Application的bind方法,并告知为独生(单例)绑定
$this->bind('events', "<一个匿名函数,如下>", true);
function ($app) {
return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
return $app->make('Illuminate\Contracts\Queue\Factory');
});
};
//继续走下去,回到Aplication的register方法,标记事件服务供应已注册
$this->markAsRegistered($provider);
//markAsRegistered方法第一行,$this['events'] 可以这样写是因为Application的父类Container实现了ArrayAccess接口
$this['events']->fire($class = get_class($provider), [$provider]);
//接着会触发Container的offsetGet方法
return $this->make('events');
//然后继续调用Application的make方法(这里需要注意下,调用的是Application->make,不是Container->make。因为$this['events'],这里的$this指的是Application)
//然而,在此处Application的make没有做任何操作,继续调用了Container的make。
//然后获取到$concrete是初始化时绑定的匿名函数Closure Object 关联 Illuminate\Events\EventServiceProvider Object
$concrete = $this->getConcrete($abstract);
//然后会走到 if($this->isBuildable($concrete, $abstract))的true分支中去,调用Container的build方法
$object = $this->build($concrete, $parameters);
//然后在build方法的第一个if中直接调用刚才绑定的Closure Object 关联 Illuminate\Events\EventServiceProvider Object
//第2个参数直接忽视,因为匿名函数只接收一个参数,php可以这么干
return $concrete($this, $parameters);
//匿名函数中实例化了调度器或者说分发器 Illuminate\Events\Dispatcher 构造函数中注入了Application
//并调用了调度器的设置队列解析器方法setQueueResolver,又传入了一个匿名函数,将其赋值给调度器的队列解析器字段$queueResolver
function () use ($app) {
return $app->make('Illuminate\Contracts\Queue\Factory');
}
//然后将调度器的实例返回,赋值给上面的$object <$object = $this->build($concrete, $parameters);>
//回到Container的make方法继续往下走,将调度器实例添加到instances中
$this->instances[$abstract] = $object;
//继续往下走,调用解决回调方法,此时,与之相关的字段都为空 globalResolvingCallbacks、resolvingCallbacks、globalAfterResolvingCallbacks、afterResolvingCallbacks
//所有没有任何回调需要解决,该方法什么也不做
$this->fireResolvingCallbacks($abstract, $object);
//继续往下走,在resolved字段标记events为(已解决)
$this->resolved[$abstract] = true;
//最终在make中返回调度器实例->offsetGet->$this['events'],然后调用它的fire方法(回到Application的markAsRegistered方法)
//其实这步什么也没有做,fire可以理解为发射、触发,然而此时调度器中没有任何事件监听需要触发
$this['events']->fire($class = 'Illuminate\Events\EventServiceProvider', ["Illuminate\Events\EventServiceProvider的实例"]);
//继续往下走,将Illuminate\Events\EventServiceProvider的实例放入Application的服务供应serviceProviders字段中
//然后在已加载的供应loadedProviders字段中标记为true
$this->loadedProviders['Illuminate\Events\EventServiceProvider'] = true;
/******Application->registerBaseServiceProviders(EventServiceProvider实例) END******/
/******Application->registerBaseServiceProviders(RoutingServiceProvider实例) BEGIN******/
//有些流程和EventServiceProvider类似的就不在详述了
//路由服务供应者注册后,会调用以下这些子方法
RoutingServiceProvider-register()
{
$this->registerRouter();
$this->registerUrlGenerator();
$this->registerRedirector();
$this->registerPsrRequest();
$this->registerPsrResponse();
$this->registerResponseFactory();
}
//registerRouter方法会触发Container的offsetSet方法绑定router
$this->app['router'] = $this->app->share(function ($app) {
return new Router($app['events'], $app);
});
//先执行Container的share方法,还是返回一个匿名函数
//所以变成了Container->bind("router", "share中返回的匿名函数(它的参数也是个匿名函数)")
//然后在bind方法中将其,绑定到Container的bindings字段中
$this->bindings['router'] = compact('share中返回的匿名函数', 'shared为false');
//同理,通过share方法绑定了url和redirect。share方法其实是一个"双重匿名的单例"
//例如:$test=share(Closure); $a=$test(); $b=$test(); 此时$a和$b公用一个实例
//接着分别绑定(bind)PsrRequest、PsrResponse和单例绑定(singleton)ResponseFactory
/******Application->registerBaseServiceProviders(RoutingServiceProvider实例) END******/
//此时,注册基础服务供应完成了,回到Application->__construct()继续注册核心容器别名
//这步很简单,就是将Application中一些固定配置的别名定义,遍历添加到Container的aliases容器中
$this->registerCoreContainerAliases();
//接着往下走,开始设置一些基础路径 例如项目根目录为:/home/wwwroot/lt lt=laravel test
if ("/home/wwwroot/lt") {
$this->setBasePath($basePath);
}
//然后在容器中注册一些路径(应用目录、项目根目录、配置文件目录、数据库目录、语言相关目录、网站入口目录、存储目录,相关文件缓存等)
//此时,实例化Illuminate\Foundation\Application完成,回到bootstrap中的app.php,继续往下走,分别注册3个单例(web内核、命令行内核、异常处理内核)
$app->singleton(
'Illuminate\Contracts\Http\Kernel',
'App\Http\Kernel'
);
$app->singleton(
'Illuminate\Contracts\Console\Kernel',
'App\Console\Kernel'
);
$app->singleton(
'Illuminate\Contracts\Debug\ExceptionHandler',
'App\Exceptions\Handler'
);
//以http内核为例,走到Container的bind方法后,由于$concrete是一个字符串,所以进入了getClosure方法
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
//Container->getClosure返回了一个匿名函数,然后绑定到Container的bindings容器中
//然后会回到index.php调用Application->make('Illuminate\Contracts\Http\Kernel');
//然后会进入Container的build方法,执行刚才绑定的匿名函数 $this->bindings['Illuminate\Contracts\Http\Kernel']['concrete']("Container自身实例",[]);
//执行匿名函数时,会进行再次build,但是这次的参数$concrete=string("App\Http\Kernel"),进入build后不会直接返回执行匿名函数,而是进行反射
$reflector = new ReflectionClass($concrete);
//如果反射失败,直接抛异常
if (! $reflector->isInstantiable()) {
throw new BindingResolutionContractException($message);
}
//然后将其暂放入建造堆栈容器中,没用到或用完后会array_pop掉
$this->buildStack[] = $concrete;
//如果反射类没有构造函数,直接把它new出来并返回,如果有父类需要检查父类是否有构造函数
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
//这里没有用到buildStack,直接array_pop掉
array_pop($this->buildStack);
return new $concrete;
}
//如果有构造函数,获取构造函数参数是ReflectionParameter的数组,如:array(0=>ReflectionParameter Object, 1=>ReflectionParameter Object ...)
$dependencies = $constructor->getParameters();
//接着走下去,keyParametersByArgument没有干任何事,继续往下调用getDependencies方法
$instances = $this->getDependencies(
$dependencies, $parameters
);
//进入getDependencies,根据当前参数,会调用resolveClass方法
foreach (array("ReflectionParameter Object app","ReflectionParameter Object router") as $parameter) {
$dependencies[] = $this->resolveClass($parameter);
}
//然后进入resolveClass方法,会再次进入Application的make方法,先说ReflectionParameter Object app
return $this->make("Illuminate\Contracts\Foundation\Application");
//此时,回到Application->make()方法,由于注册过别名,所以$abstract变成了其别名:app
//然后继续调用Container->make("app",[]);
//然后在Container->instances中找到了'app'对应的实例 Illuminate\Foundation\Application Object ...
//然后回到Container的getDependencies方法,将实例添加到$dependencies数组
//然后进入下一次循环,再次调用Application->make
return $this->make('Illuminate\Routing\Router');
//然后别名后调用Container->make
return parent::make('router', []);
//然后进入build方法,得到之前绑定的匿名函数$this->bindings['router']['concrete']
//继续往下走,在resolved字段标记router为(已解决)
$this->resolved[$abstract] = true;
//然后回到Container的getDependencies方法,将匿名函数添加到$dependencies数组
//然后返回$dependencies数组,回到build方法
//然后释放掉buildStack,这里其实并没有用到它
array_pop($this->buildStack);
//然后,调用反射类的实例方法,传入刚才返回的$dependencies数组
return $reflector->newInstanceArgs($instances);
//然后一路返回至Container->make中的第一次build处
"App\Http\Kernel Object" = $this->build("Illuminate\Contracts\Http\Kernel", []);
//然后继续走下去,将刚才反射出来的"App\Http\Kernel Object"放入instances容器
if ($this->isShared("Illuminate\Contracts\Http\Kernel") == true) {
$this->instances["Illuminate\Contracts\Http\Kernel"] = "App\Http\Kernel Object";
}
//继续往下走,在resolved字段标记Illuminate\Contracts\Http\Kernel为(已解决)
$this->resolved[$abstract] = true;
//此时,make("Illuminate\Contracts\Http\Kernel")完成了,回到index.php
//继续执行,调用父类Illuminate\Foundation\Http\Kernel\handle方法,需要传入request参数
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
//然后进入获取$request对象流程,laravel的Request底层使用了symfony组件,
//调用Symfony\Component\HttpFoundation\Request的静态方法,将其静态字段标记为true
//$httpMethodParameterOverride,大致意思为:http方法参数重写
static::enableHttpMethodParameterOverride();
//然后回到capture方法,capture翻译为:捕获,调用Illuminate\Http\Request的createFromBase方法
return static::createFromBase(SymfonyRequest::createFromGlobals());
//此时,需要先通过SymfonyRequest将$_GET、$_POST、$_COOKIE、$_FILES、$_SERVER等全局变量封装到它的相关字段中并将其自身实例化
//$_GET==$query $_POST==$request $_COOKIE==$cookies $_FILES==$files $_SERVER==$server
//调用createFromGlobals再调用createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $server)
//然后进入createRequestFromFactory方法会调用new static,跟new get_class($this)效果类似
//实例化了Symfony\Component\HttpFoundation\Request
return new static($query, $request, $attributes, $cookies, $files, $server, $content);
//然后进入Symfony\Component\HttpFoundation\Request的__construct调用initialize方法
$this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
//然后将各个参数封装成ParameterBag对象或者继承ParameterBag的对象Symfony\Component\HttpFoundation\Request的各个相关字段
//然后会进入Illuminate\Http\Request->createFromBase并将刚才实例化的SymfonyRequest传入
//这个判断不会进入,因为调用方是子类,而$request是通过父类的new static延迟静态绑定的
if ($request instanceof static) {
return $request;
}
//然后通过(new static)->duplicate,实例化自己Illuminate\Http\Request,并调用duplicate方法,duplicate中调用了父类的duplicate
//duplicate是复制的意思,把Illuminate\Http\Request复制一份,赋值相应参数,并返回
//然后走下去,将$request->request 重置为 GET|POST|JSON(如果是json的话,会转成array)的参数,并返回
//此时回到了index.php,进入$kernel的handle方法,传入Illuminate\Http\Request的副本
//将副本的$httpMethodParameterOverride设置为ture,并调用Kernel的sendRequestThroughRouter方法
//然后设置Container的instances字段容器"request"=>"Illuminate\Http\Request副本"
//然后进行初始化,$this->bootstrap()
$bootstrappers = [
'Illuminate\Foundation\Bootstrap\DetectEnvironment', /*检查环境 使用Dotenv做一些初始化环境配置 将/.env加载到$_SERVER $_ENV中,
然后绑定$app->bindings['env'] = 一个匿名函数返回APP_ENV的值
*/
'Illuminate\Foundation\Bootstrap\LoadConfiguration', /*加载配置 将/config下的配置文件全部加载到Illuminate\Config\Repository的items中,
并将Illuminate\Config\Repository Object放入Application->instances['config'],
设置时区、编码等
*/
'Illuminate\Foundation\Bootstrap\ConfigureLogging', /*日志配置 实例化Illuminate\Log\Writer(注入Monolog和$app->bindings["events"]),
并将其注册到$app->instances['log'],然后初始化日志方式(文件)、路径、格式(format)等
*/
'Illuminate\Foundation\Bootstrap\HandleExceptions', //设置错误日志级别、设置自定义错误处理、设置自定义异常处理、设置自定义shutdown处理等
'Illuminate\Foundation\Bootstrap\RegisterFacades', /*设置别名自动加载 在spl_autoload_register函数队列首部插入别名加载class_alias,
如果new的类名是config/app.php中的aliases数组的key,将key作为value的别名
*/
'Illuminate\Foundation\Bootstrap\RegisterProviders', //通过Illuminate\Foundation\ProviderRepository注册services.json下的相关服务供应商
'Illuminate\Foundation\Bootstrap\BootProviders', //执行收尾工作,如果$app->serviceProviders有boot方法,调用相应的boot方法
];
$this->app->bootstrapWith($bootstrappers);
//进入bootstrapWith方法,循环将$bootstrappers做相应初始化
foreach ($bootstrappers as $bootstrapper) {
//在初始化之前挂载事件监听,暂时什么都不干
$this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);
//这一步,实例化相应的对象,并在容器中将它标识为已解决 $this->resolved[$abstract] = true;
//然后调用对象的初始化方法 $obj->bootstrap(Application $app);
$this->make($bootstrapper)->bootstrap($this);
//在初始化之前挂载事件监听,暂时什么都不干
$this['events']->fire('bootstrapped: '.$bootstrapper, [$this]);
}
//初始化完成后,回到Illuminate\Foundation\Http\Kernel->handle()->sendRequestThroughRouter()
//然后实例化Illuminate\Pipeline\Pipeline并做相应操作 pipeline流程 输入->管道加工->输出
//构造函数传入$app,send传入传输参数($request),through传入需要经过的加工处理的管道|流水线($middleware中间件),then执行相应的目标方法
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
//send和through只是一些设置工作,then方法比较复杂,详细说一下then方法
//$firstSlice可以理解为Illuminate\Foundation\Http\Kernel->dispatchToRouter()返回的匿名函数
$firstSlice = $this->getInitialSlice($destination);
//将如下数组($this->pipes)倒序排序,因为下面call_user_func的时候是从匿名函数的最里层开始调用的
array (
'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
'App\Http\Middleware\EncryptCookies',
'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
'Illuminate\Session\Middleware\StartSession',
'Illuminate\View\Middleware\ShareErrorsFromSession',
'App\Http\Middleware\VerifyCsrfToken',
)
$pipes = array_reverse($this->pipes);
// $pipes上面的数组倒序、$this->getSlice()返回一个匿名函数、$firstSlice也是一个匿名函数,$this->passable就是$request
// array_reduce($pipes, $this->getSlice(), $firstSlice)返回一个递归后的匿名函数。
return call_user_func(
array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable
);
//执行call_user_func后会依次执行对上面的array中的类名进行make->build->反射->调用其handle方法,handle的参数是$request和$firstSlice或上一次执行的返回值
//首先调用$firstSlice,其实就是Illuminate\Routing\Router的dispatch方法
//然后进入dispatch方法,刚开始$response为NULL,将$request分发到路由后返回Response
$response = $this->dispatchToRoute($request);
//然后findRoute、然后Illuminate\Routing\RouteCollection->match
$route = $this->findRoute($request);
$this->routes->match($request);
//进入match方法
$routes = $this->get($request->getMethod());
//然后会走到Illuminate\Support\Arr::get方法
return Arr::get($this->routes, $method, []);
//Arr::get()中第一个参数$this->routes是之前Illuminate\Foundation\Bootstrap\BootProviders->bootstrap()的时候赋值的
//App\Providers\RouteServiceProvider->boot()
//$this->app[UrlGenerator::class]->setRootControllerNamespace($this->namespace);
//UrlGenerator::class => Illuminate\Contracts\Routing\UrlGenerator 别名为url
//然后会执行Illuminate\Routing\RoutingServiceProvider->registerUrlGenerator绑定的匿名函数
//然后回到App\Providers\RouteServiceProvider->boot()进入$this->loadRoutes();
//然后调用$this->app->call([$this, 'map']); return call_user_func_array($callback, $dependencies);
//然后会调用App\Providers\RouteServiceProvider->map()
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routes.php');
});
//然后在Illuminate\Routing\Router->group()中给groupStack赋值
$this->groupStack[] = array("namespace" => "App\Http\Controllers");
//并载入/home/wwwroot/lt/app/Http/routes.php
Route::get('/', function () {
return view('welcome');
});
//Illuminate\Routing\Router->get()->addRoute()
return $this->routes->add($this->createRoute(['GET', 'HEAD'], '/', function(){return view('welcome');}));
//Illuminate\Routing\Router->createRoute()
$route = $this->newRoute($methods, $this->prefix($uri), $action);
//Illuminate\Routing\Router->newRoute()
return (new Route($methods, $uri, $action))->setContainer($this->container);
//Illuminate\Routing\Router->createRoute()->mergeWithLastGroup()->mergeGroup()
$this->mergeGroupAttributesIntoRoute($route);
$route->setAction($action);
//Illuminate\Routing\Router->createRoute()
$this->addWhereClausesToRoute($route);
//Illuminate\Routing\RouteCollection->add
$this->addToCollections($route);
//Illuminate\Routing\RouteCollection->addToCollections
//该方法中为$this->routes赋值(上面有提到过),并为allRoutes赋值(foreach的最后一个key.$domainAndUri)
$domainAndUri = $route->domain().$route->getUri();
foreach ($route->methods() as $method) {
$this->routes[$method][$domainAndUri] = $route;
}
$this->allRoutes[$method.$domainAndUri] = $route;
//Illuminate\Routing\RouteCollection->add->addLookups 如果设置别名或者controller作相应处理
//回到Illuminate\Routing\RouteCollection->match,$routes=array("/"=>Illuminate\Routing\Route Object)
$routes = $this->get($request->getMethod());
$route = $this->check($routes, $request);
//Illuminate\Routing\RouteCollection->match->check
return Arr::first($routes, function ($key, $value) use ($request, $includingMethod) {
return $value->matches($request, $includingMethod);
});
//Illuminate\Routing\Route->matches
$this->compileRoute();
//Illuminate\Routing\Route->compileRoute
$this->compiled = with( new SymfonyRoute($uri, $optionals, $this->wheres, [], $this->domain() ?: '') )->compile();
//Symfony\Component\Routing\Route->compile 返回一个Symfony\Component\Routing\CompiledRoute Object
return $this->compiled = Symfony\Component\Routing\RouteCompiler::compile($this);
//Illuminate\Routing\RouteCollection->match 做一些相应的绑定操作,然后返回Illuminate\Routing\Route Object
return $route->bind($request);
//然后回到Illuminate\Routing\Router->findRoute方法,将match返回的Illuminate\Routing\Route Object赋值给$this->current并注册到$app->instances
$this->container->instance('Illuminate\Routing\Route', $route);
//然后回到Illuminate\Routing\Router->dispatchToRoute()继续往下走,$request->setRouteResolver()后,生成$response对象
$response = $this->runRouteWithinStack($route, $request);
//进入Illuminate\Routing\Router->runRouteWithinStack,再来一次pipeline流程,但是这次中间件$middleware为空,所以只是执行then中的匿名函数并返回
return (new Pipeline($this->container))
->send($request)
->through($middleware)
->then(function ($request) use ($route) {
return $this->prepareResponse(
$request,
$route->run($request)
);
});
//执行return $this->prepareResponse($request, $route->run($request)); 先执行 $route->run($request)
//会调用 lt/app/http/routes.php中的 return view('welcome');
//然后调用helpers.php中的view函数,然后会调用$app->make("Illuminate\Contracts\View\Factory")
//Illuminate\Contracts\View\Factory的别名是view,所以会执行之前初始化时候绑定的$app->bindings['view']所对应的匿名函数
//Closure Object 关联 Illuminate\View\ViewServiceProvider Object
//然后会执行 $app['view.engine.resolver'] 返回Illuminate\View\EngineResolver Object 并给它的resolvers字段设置2个匿名函数并在$app中注册一个blade.compiler绑定
//$engine->resolvers['php']=Closure Object 关联 Illuminate\View\ViewServiceProvider Object
//$engine->resolvers['blade']=Closure Object 关联 Illuminate\View\ViewServiceProvider Object
//然后执行 $app['view.finder'] 返回Illuminate\View\FileViewFinder Object
//然后实例化Illuminate\View\Factory
$env = new Factory('Illuminate\View\EngineResolver Object', 'Illuminate\View\FileViewFinder Object', 'Illuminate\Events\Dispatcher Object');
//然后回到helpers.php的view函数($factory就是上面返回的$env)
return $factory->make($view, $data, $mergeData);
//找到welcome文件的路径 /home/wwwroot/lt/resources/views/welcome.blade.php
$path = $this->finder->find($view);
//然后继续往下走会返回一个view对象
$this->callCreator($view = new View($this, $this->getEngineFromPath($path), $view, $path, $data));
return $view;
//$this->getEngineFromPath($path) 会执行刚才绑定的$engine->resolvers['blade']的匿名函数
//匿名函数返回一个Illuminate\View\Engines\CompilerEngine Object
//该对象注入了 Illuminate\View\Compilers\BladeCompiler Object
//回到Illuminate\Routing\Router->prepareResponse 实例化Illuminate\Http\Response extends Symfony\Component\HttpFoundation\Response
$response = new Response('Illuminate\View\View Object');
//然后预处理下$request并返回Response对象
return $response->prepare($request);
//然后回到Illuminate\Routing\Router->dispatchToRoute 后续操作暂时都没执行 return $response;
//然后回到最上面的pipeline流程
//调用Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode的handle
//检查/home/wwwroot/lt/storage/framework/down是否存在,有就返回503错误
//调用App\Http\Middleware\EncryptCookies对cookie进行加解密
//调用Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse
//调用Illuminate\Session\Middleware\StartSession进行session驱动设置,session_start等
//调用Illuminate\View\Middleware\ShareErrorsFromSession
//调用App\Http\Middleware\VerifyCsrfToken验证CSFR令牌
//然后返回经过流水线处理的$response对象,回到index.php,输出头信息和内容,此时会输出laravel的welcome页面
$response->send();
//最后做一些后续操作,之前用到的中间件如果有terminate方法,执行它
//这里只有Illuminate\Session\Middleware\StartSession有terminate方法,执行它做一些SESSION的后续操作
//laravel中操作session是在内存中(对象)操作的,最后结束时将其"持久化"到文件中
$kernel->terminate($request, $response);