Laravel学习之启动过程

先说几句废话,调和气氛。事情的起由来自客户需求频繁变更,伟大的师傅决定横刀立马的改革使用新的框架(created by 师傅)。在他老人家为时半小时对其新框架代码目录简要的讲解后,我依然一脸懵逼(准确来讲,他可能最需要只是鄙人快速上手,照猫画虎,知道HOW就行了,迅速完成代码改造TODO。)

而我一脸懵逼的原因是:对于照猫画虎,迅速完成TODO我还是自信可以的,但我真正感冒的并不是这个,依我的性格,要么已经知道why了,没必要再去考究,为了工期迅速完成工作(如果能有所改革,那最好不过了。);要么不知道why,慢慢的探索研究,发现乐趣并同时完成工作;但要我如盲人摸象一样,茫茫然的重复劳动,我一定是会拒绝的。。。工期嘛,科科。。。就是这么草率。。。(据说该新框架是聚百家之所长的杂糅产物,既有Laravel的优雅知性,又兼具CI的简洁明了,但木有文档。。。。。无论如何,出于好奇心,我还是一腔鸡血的开始了膜拜师傅伟大的框架的进程~~

新框架的知晓过程:首先,粗糙的浏览了下其文件目录结构,同laravel类似,其所有应用请求的入口是backend/index.php,它做了这些事:1.Composer的自动加载;2. 设置路由规则,可能由于未看过其vendor中源代码,看起来略有不适;3. loadAllControllersInDirectoryAsCI 呃,加载控制器目录?估计是为了命名空间?(待尝试以验证)4. handleRequestThroughAdah处理应用请求; 其次,暂且不探究这让我略奇怪的路由规则(maybe 我太渣)和黑盒子中如何处理响应请求的,在悠悠的看了剩余的目录结构外,只能说:照猫画虎的用还是能用的,但这不顺手的不适感若不去除,我很难过。。。。所以我想是不是因为我几乎没怎么接触过laravel框架的缘故?

Laravel框架的工作原理

快速的根据文档https://docs.golaravel.com/docs/5.4/lifecycle/#focus-on-service-providers, 简明扼要的全面了解下Laravel的工作原理。

请求入口

一个 Laravel 应用的所有请求的入口都是public/index.php文件。index.php做了这几件事:1.载入 Composer 生成的自动加载器定义, /vendor/autoload.php(至于composer自动加载的奥妙此处暂不详解);2. bootstrap/app.php文件获取到 Laravel 应用实例。3. 创建一个自身应用实例 /服务容器,然后handle request 、send response and terminate.

tip:关于类自动加载的具体细节可参见博客文章:http://www.cnblogs.com/lpfuture/p/5578274.html,我们直接关注laravel的核心:服务容器。

服务容器

服务容器,也叫IOC容器,其实包含了依赖注入(DI)和控制反转(IOC)两部分,是laravel的真正核心。而larvavel的其他各种功能模块比如 Route(路由)、Eloquent ORM(数据库 ORM 组件)、Request and Response(请求和响应)等等,实际上都是与核心无关的类模块提供的,这些类从注册到实例化,最终被你所使用,其实都是 laravel 的服务容器负责的。服务容器的概念我们一步步来解释:

IOC容器诞生的故事——石器时代(原始模式)

举个荔枝,我们有一个“超人”类,超人肯定拥有不止一个超能力,这些超能力可以抽象化定义为一个个描述它的类,比如一个超能力肯定有多种属性、(操作)方法等。。。目前,我们先大致定义个超能力的“力量”类,然后让“超人”类在构造函数中被赋予“力量”的超能力,形势如下:

我们看到了一点,“超人”和“力量类”之间不可避免的产生了一个依赖。这种依赖在面向对象编程项目中是随处可见的,少量的依赖并不会有太过直观的影响,我们随着这个例子逐渐铺开,大家会慢慢意识到当依赖达到一个量级时,是怎样一番噩梦般的体验。

现在我们将超能力继续多元化,假设超人还可以具有以下多种超能力,那么超人现在的形式如下:

飞行,属性有:飞行速度、持续飞行时间

力量,属性是力量值

能量弹,属性有:伤害值、射击距离、同时射击个数

我们要手动在构造函数(或其他方法)内实例化一系列需要的类,这样:增加或者变更超能力时,必须重新改造超人。这时,有人灵机一动想到:既然超人的能力可以被随时更换,为何不做成添加或者更新一个芯片呢?

IOC容器诞生的故事——青铜时代(工厂模式)

此时,我们不再在“超人”类中固化 “超能力” 初始化的行为,而转由外部负责,由外部创造超能力模组、装置或者芯片等(我们后面统一称为 “模组”),植入超人体内的某一个接口,这个接口是一个既定的,只要这个 “模组” 满足这个接口的装置都可以被超人所利用,可以提升、增加超人的某一种能力。这种由外部负责其依赖需求的行为,我们可以称其为 “控制反转(IOC)”。

工厂模式,顾名思义,就是一个类所以依赖的外部事物的实例,都可以被一个或多个 “工厂” 创建的这样一种开发模式,就是 “工厂模式”。我们为了给超人制造超能力模组,我们创建了一个工厂,它可以制造各种各样的模组,且仅需要通过一个方法:

诺,现在,“超人” 的创建不再依赖任何一个 “超能力” 的类,我们如若修改了或者增加了新的超能力,只需要针对修改 SuperModuleFactory 即可。扩充超能力的同时不再需要重新编辑超人的类文件,但是,这才刚刚开始。

IOC容器诞生的故事——铁器时代(依赖注入)

正如我们所看到的,由“超人”对“超能力”的依赖变成超人“超能力模组工厂”的依赖后,对付小怪兽更加得心应手,但依赖并未解除,假如工厂出了点麻烦,问题就变得很棘手。

多数情况下,工厂模式已经足够了,但工厂模式的缺点是:接口未知(没有契约模型)、产生对象单一。由于工厂模式下,所有的模组都已经在工厂中安排好了(统一的接口),如果有新的、高级模组加入时,我们必须修改工厂类(类似增加新的生产线)。噩梦即将到来,引入我们的主要配角:DI(依赖注入)。

由于对超能力模组的需求不断增大,扩展生产线倒是其次的,重要的是高智商的大神们创造出的超能力模组没有统一的接口,自然而然无法被正常使用。这时我们需要提出一种契约,这样无论是谁创造出的模组,都符合这样的接口,自然就可被正常使用,然后有了如下形式。

这样我们可以创造多个超人,分别注入需要的超能力模组即可(虽然一个超人只有一个超能力。。。。。)

现在你可能会疑问,说好的重要配角“依赖注入”呢?其实,本文从开头到现在提到的一系列依赖,只要不是由内部生产(比如初始化、构造函数 __construct 中通过工厂方法、自行手动 new 的),而是由外部以参数或其他形式注入的,都属于 依赖注入(DI) 。事实上,就是这么简单。下面就是一个典型的依赖注入:

理解了依赖注入,我们就可以继续深入问题。慢慢走近今天的主角……

IOC容器诞生的故事——科技时代(IOC容器)

回头看看上面“铁器时代”手动创建超人并注入刚刚创建的超能力模组,手动。。。,显然,我们其实还是更多的自动化。这种更为高级的工厂,就是工厂模式的升华 —— IOC容器,形式如下:

这就是一个粗糙的容器,有点摸不着头脑,来,我们先看下how,如何使用。

$container= new Container();//创建一个容器(后面简称为超级工厂)

$container->bind('superman',function($container,$moduleName) {return new Superman($container->make($moduleName));

});// 向该 超级工厂 添加 超人 的生产脚本

$container->bind('xpower',function($container) {return new XPower;});// 向该 超级工厂 添加 超能力模组 的生产脚本

$container->bind('ultrabomb',function($container) {returnnew UltraBomb;});// 同上******************  华丽丽的分割线  **********************

$superman_1=$container->make('superman','xpower');//启动生产Superman

$superman_2 =$container->make('superman','ultrabomb');

So,通过最初的 绑定(bind) 操作,我们向 超级工厂 注册了一些生产脚本,这些生产脚本在生产指令下达之时便会执行。我们彻底的解除了 超人 与 超能力模组 的依赖关系,更重要的是,容器类也丝毫没有和他们产生任何依赖!我们通过注册、绑定的方式向容器中添加一段可以被执行的回调(可以是匿名函数、非匿名函数、类的方法)作为生产一个类的实例的 脚本 ,只有在真正的 生产(make) 操作被调用执行时,才会触发。

实际上,真正的 IOC容器更为高级。我们现在的例子中,还是需要手动提供超人所需要的模组参数,但真正的 IOC容器会根据类的依赖需求,自动在注册、绑定的一堆实例中搜寻符合的依赖需求,并自动注入到构造函数中。

laravel初始化一个服务容器的大概过程

这就要拉出源码溜溜了(好在我们能站在巨人的肩膀上~~)。。。初始化服务容器的相关调度文件就是:/bootstrap/app.php...

然后在跟随大神的👣,读了三个


代码清单/bootstrap/app.php

singleton('Illuminate\Contracts\Http\Kernel','App\Http\Kernel');//单例一个App\Console\Kernel对象,可以使用App::make('Illuminate\Contracts\Console\Kernel')调用$app->singleton('Illuminate\Contracts\Console\Kernel','App\Console\Kernel');//打字好累,同上,不解释$app->singleton('Illuminate\Contracts\Debug\ExceptionHandler','App\Exceptions\Handler');//返回一个初始化完成的服务容器return$app;

代码清单Illuminate\Foundation\Application

//代码太多,只能解释几个主要的方法(真实情况是,我了解也不多,也就看了这几个方法*^_^*)publicfunction__construct($basePath = null)    {//初始化最简单的容器$this->registerBaseBindings();//在容器中注册最基本的服务提供者(即ServiceProvider)$this->registerBaseServiceProviders();//在容器中注册一些核心类的别名(这个说法貌似有点不妥,可以参见以下的代码注释自己再理解一下)$this->registerCoreContainerAliases();//在容器中注册一些常用的文档绝对路径if ($basePath)$this->setBasePath($basePath);    }protectedfunctionregisterBaseBindings()    {//初始化一个空的容器static::setInstance($this);//在容器中,实例化一个key为app的实例,相对的值就是当前容器,你可以使用App::make('app')来取得一个容器对象$this->instance('app',$this);//同上$this->instance('Illuminate\Container\Container',$this);    }protectedfunctionregisterBaseServiceProviders()    {//EventServiceProvider这个服务提供者,其实是向容器注册了一个key为events的对象,可以在你的IDE里面追踪一下代码$this->register(new EventServiceProvider($this));//注册4个key分别为router、url、redirect、Illuminate\Contracts\Routing\ResponseFactory的对象$this->register(new RoutingServiceProvider($this));    }/*这个方法的作用,就以一个例子来解释吧(语文不太好~\(≧▽≦)/~)        在调用此方法之前,我们想取得一个容器实例的做法是 App::make('app');        现在我们可以使用App::make('Illuminate\Foundation\Application')        App::make('Illuminate\Contracts\Container\Container')        App::make('Illuminate\Contracts\Foundation\Application')        三种方法来取得一个容器实例,即Illuminate\Foundation\Application、Illuminate\Contracts\Container\Container、Illuminate\Contracts\Foundation\Application三者都是app的别名;    */publicfunctionregisterCoreContainerAliases()    {$aliases =array('app'                  => ['Illuminate\Foundation\Application','Illuminate\Contracts\Container\Container','Illuminate\Contracts\Foundation\Application'],'artisan'              => ['Illuminate\Console\Application','Illuminate\Contracts\Console\Application'],'auth'                =>'Illuminate\Auth\AuthManager','auth.driver'          => ['Illuminate\Auth\Guard','Illuminate\Contracts\Auth\Guard'],'auth.password.tokens' =>'Illuminate\Auth\Passwords\TokenRepositoryInterface','blade.compiler'      =>'Illuminate\View\Compilers\BladeCompiler','cache'                => ['Illuminate\Cache\CacheManager','Illuminate\Contracts\Cache\Factory'],'cache.store'          => ['Illuminate\Cache\Repository','Illuminate\Contracts\Cache\Repository'],'config'              => ['Illuminate\Config\Repository','Illuminate\Contracts\Config\Repository'],'cookie'              => ['Illuminate\Cookie\CookieJar','Illuminate\Contracts\Cookie\Factory','Illuminate\Contracts\Cookie\QueueingFactory'],'encrypter'            => ['Illuminate\Encryption\Encrypter','Illuminate\Contracts\Encryption\Encrypter'],'db'                  =>'Illuminate\Database\DatabaseManager','events'              => ['Illuminate\Events\Dispatcher','Illuminate\Contracts\Events\Dispatcher'],'files'                =>'Illuminate\Filesystem\Filesystem','filesystem'          =>'Illuminate\Contracts\Filesystem\Factory','filesystem.disk'      =>'Illuminate\Contracts\Filesystem\Filesystem','filesystem.cloud'    =>'Illuminate\Contracts\Filesystem\Cloud','hash'                =>'Illuminate\Contracts\Hashing\Hasher','translator'          => ['Illuminate\Translation\Translator','Symfony\Component\Translation\TranslatorInterface'],'log'                  => ['Illuminate\Log\Writer','Illuminate\Contracts\Logging\Log','Psr\Log\LoggerInterface'],'mailer'              => ['Illuminate\Mail\Mailer','Illuminate\Contracts\Mail\Mailer','Illuminate\Contracts\Mail\MailQueue'],'paginator'            =>'Illuminate\Pagination\Factory','auth.password'        => ['Illuminate\Auth\Passwords\PasswordBroker','Illuminate\Contracts\Auth\PasswordBroker'],'queue'                => ['Illuminate\Queue\QueueManager','Illuminate\Contracts\Queue\Factory','Illuminate\Contracts\Queue\Monitor'],'queue.connection'    =>'Illuminate\Contracts\Queue\Queue','redirect'            =>'Illuminate\Routing\Redirector','redis'                => ['Illuminate\Redis\Database','Illuminate\Contracts\Redis\Database'],'request'              =>'Illuminate\Http\Request','router'              => ['Illuminate\Routing\Router','Illuminate\Contracts\Routing\Registrar'],'session'              =>'Illuminate\Session\SessionManager','session.store'        => ['Illuminate\Session\Store','Symfony\Component\HttpFoundation\Session\SessionInterface'],'url'                  => ['Illuminate\Routing\UrlGenerator','Illuminate\Contracts\Routing\UrlGenerator'],'validator'            => ['Illuminate\Validation\Factory','Illuminate\Contracts\Validation\Factory'],'view'                => ['Illuminate\View\Factory','Illuminate\Contracts\View\Factory'],        );foreach ($aliasesas$key =>$aliases)        {foreach ((array)$aliasesas$alias)            {$this->alias($key,$alias);

}

}

}

由此得到的一个容器实例

Application {#2 ▼#basePath: "/Applications/XAMPP/xamppfiles/htdocs/laravel"#hasBeenBootstrapped: false#booted: false#bootingCallbacks: []#bootedCallbacks: []#terminatingCallbacks: []#serviceProviders: array:2 [▶]#loadedProviders: array:2 [▶]#deferredServices: []#storagePath: null#environmentFile: ".env"#resolved: array:1 [▶]#bindings: array:8 [▼"events" =>array:2 [▶]"router" =>array:2 [▶]"url" =>array:2 [▶]"redirect" =>array:2 [▶]"Illuminate\Contracts\Routing\ResponseFactory" =>array:2 [▶]"Illuminate\Contracts\Http\Kernel" =>array:2 [▶]"Illuminate\Contracts\Console\Kernel" =>array:2 [▶]"Illuminate\Contracts\Debug\ExceptionHandler" =>array:2 [▶]  ]#instances: array:10 [▼"app" => Application {#2}"Illuminate\Container\Container" => Application {#2}"events" => Dispatcher {#5 ▶}"path" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/app""path.base" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel""path.config" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/config""path.database" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/database""path.lang" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/resources/lang""path.public" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/public""path.storage" =>"/Applications/XAMPP/xamppfiles/htdocs/laravel/storage"  ]#aliases: array:59 [▼"Illuminate\Foundation\Application" =>"app""Illuminate\Contracts\Container\Container" =>"app""Illuminate\Contracts\Foundation\Application" =>"app""Illuminate\Console\Application" =>"artisan""Illuminate\Contracts\Console\Application" =>"artisan""Illuminate\Auth\AuthManager" =>"auth""Illuminate\Auth\Guard" =>"auth.driver""Illuminate\Contracts\Auth\Guard" =>"auth.driver""Illuminate\Auth\Passwords\TokenRepositoryInterface" =>"auth.password.tokens""Illuminate\View\Compilers\BladeCompiler" =>"blade.compiler""Illuminate\Cache\CacheManager" =>"cache""Illuminate\Contracts\Cache\Factory" =>"cache""Illuminate\Cache\Repository" =>"cache.store""Illuminate\Contracts\Cache\Repository" =>"cache.store""Illuminate\Config\Repository" =>"config""Illuminate\Contracts\Config\Repository" =>"config""Illuminate\Cookie\CookieJar" =>"cookie""Illuminate\Contracts\Cookie\Factory" =>"cookie""Illuminate\Contracts\Cookie\QueueingFactory" =>"cookie""Illuminate\Encryption\Encrypter" =>"encrypter""Illuminate\Contracts\Encryption\Encrypter" =>"encrypter""Illuminate\Database\DatabaseManager" =>"db""Illuminate\Events\Dispatcher" =>"events""Illuminate\Contracts\Events\Dispatcher" =>"events""Illuminate\Filesystem\Filesystem" =>"files""Illuminate\Contracts\Filesystem\Factory" =>"filesystem""Illuminate\Contracts\Filesystem\Filesystem" =>"filesystem.disk""Illuminate\Contracts\Filesystem\Cloud" =>"filesystem.cloud""Illuminate\Contracts\Hashing\Hasher" =>"hash""Illuminate\Translation\Translator" =>"translator""Symfony\Component\Translation\TranslatorInterface" =>"translator""Illuminate\Log\Writer" =>"log""Illuminate\Contracts\Logging\Log" =>"log""Psr\Log\LoggerInterface" =>"log""Illuminate\Mail\Mailer" =>"mailer""Illuminate\Contracts\Mail\Mailer" =>"mailer""Illuminate\Contracts\Mail\MailQueue" =>"mailer""Illuminate\Pagination\Factory" =>"paginator""Illuminate\Auth\Passwords\PasswordBroker" =>"auth.password""Illuminate\Contracts\Auth\PasswordBroker" =>"auth.password""Illuminate\Queue\QueueManager" =>"queue""Illuminate\Contracts\Queue\Factory" =>"queue""Illuminate\Contracts\Queue\Monitor" =>"queue""Illuminate\Contracts\Queue\Queue" =>"queue.connection""Illuminate\Routing\Redirector" =>"redirect""Illuminate\Redis\Database" =>"redis""Illuminate\Contracts\Redis\Database" =>"redis""Illuminate\Http\Request" =>"request""Illuminate\Routing\Router" =>"router""Illuminate\Contracts\Routing\Registrar" =>"router""Illuminate\Session\SessionManager" =>"session""Illuminate\Session\Store" =>"session.store""Symfony\Component\HttpFoundation\Session\SessionInterface" =>"session.store""Illuminate\Routing\UrlGenerator" =>"url""Illuminate\Contracts\Routing\UrlGenerator" =>"url""Illuminate\Validation\Factory" =>"validator""Illuminate\Contracts\Validation\Factory" =>"validator""Illuminate\View\Factory" =>"view""Illuminate\Contracts\View\Factory" =>"view"  ]#extenders: []#tags: []#buildStack: []  +contextual: []#reboundCallbacks: []#globalResolvingCallbacks: []#globalAfterResolvingCallbacks: []#resolvingCallbacks: []#afterResolvingCallbacks: []

}

怎么打印一个实例??

到这一步为止,你可以这样做dd(app())

dd(app())什么意思??

这里包含两个方法dd()和app(),具体定义请看自动加载的第四种方法

那说好的App::make(‘app’)方法咋不能用呢?

这是因为这个方法需要用到Contracts,而到此为止,还未定义App作为Illuminate\Support\Facades\App的别名,因而不能用;需要等到统一入口文件里面的运行Kernel类的handle方法才能用,所以在Controller里面是可以用的,现在不能用

到此为止,一个容器实例就诞生了,事情就是这么个事情,情况就是这个个情况,再具体的那就需要你自己去看代码了,我知道的就这些

启动Kernel代码

Kernel实例调用handle方法,意味着laravel的核心和公用代码已经准备完毕,此项目正式开始运行

代码清单/app/Http/Kernel.php

'App\Http\Middleware\Authenticate','auth.basic' =>'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth','guest' =>'App\Http\Middleware\RedirectIfAuthenticated','test' =>'App\Http\Middleware\testMiddleWare',

];

}

大家看到了,其实这个文件里面没有handle方法,只有一些属性定义,所以真正的handle方法,实在父类里面实现的

代码清单…/Illuminate/Foundation/Http/Kernel.php

//好多代码,见几个我看过的扯扯,其他的期待你们补上//这个很重要,是项目的一些启动引导项,Kernel的重要步骤中,首先就是启动这些文件的bootstrap方法protected$bootstrappers = [//检测环境变量文件是否正常'Illuminate\Foundation\Bootstrap\DetectEnvironment',//取得配置文件,即把/config/下的所有配置文件读取到容器(app()->make('config')可以查看所有配置信息)'Illuminate\Foundation\Bootstrap\LoadConfiguration',//绑定一个名字为log的实例到容器,怎么访问??(app()->make('log'))'Illuminate\Foundation\Bootstrap\ConfigureLogging',//设置异常抓取信息,这个还没仔细看,但大概就是这个意思'Illuminate\Foundation\Bootstrap\HandleExceptions',//把/config/app.php里面的aliases项利用PHP库函数class_alias创建别名,从此,我们可以使用App::make('app')方式取得实例'Illuminate\Foundation\Bootstrap\RegisterFacades',//把/config/app.php里面的providers项,注册到容器'Illuminate\Foundation\Bootstrap\RegisterProviders',//运行容器中注册的所有的ServiceProvider中得boot方法'Illuminate\Foundation\Bootstrap\BootProviders',    ];//真正的handle方法publicfunctionhandle($request)    {try        {//主要是这行,调度了需要运行的方法return$this->sendRequestThroughRouter($request);        }catch (Exception$e)        {$this->reportException($e);return$this->renderException($request,$e);        }    }protectedfunctionsendRequestThroughRouter($request)    {$this->app->instance('request',$request);        Facade::clearResolvedInstance('request');//运行上述$bootstrappers里面包含的文件的bootstrap方法,运行的作用,上面已经注释$this->bootstrap();//这是在对URL进行调度之前,也就是运行Route之前,进行的一些准备工作return (new Pipeline($this->app))//不解释                    ->send($request)//继续不解释//需要运行$this->middleware里包含的中间件                    ->through($this->middleware)//运行完上述中间件之后,调度dispatchToRouter方法,进行Route的操作                    ->then($this->dispatchToRouter());    }//前奏执行完毕之后,进行Route操作protectedfunctiondispatchToRouter()    {returnfunction($request)        {$this->app->instance('request',$request);//跳转到Router类的dispatch方法return$this->router->dispatch($request);

};

}

下面就需要根据URL和/app/Http/routes.php文件,进行Route操作

文件清单…/Illuminate/Routing/Router.php

//代码好多,挑几个解释publicfunctiondispatch(Request$request)    {$this->currentRequest =$request;//在4.2版本里面,Route有一个筛选属性;5.0之后的版本,被Middleware代替$response =$this->callFilter('before',$request);if (is_null($response))        {//继续调度$response =$this->dispatchToRoute($request);        }$response =$this->prepareResponse($request,$response);//在4.2版本里面,Route有一个筛选属性;5.0之后的版本,被Middleware代替$this->callFilter('after',$request,$response);return$response;    }publicfunctiondispatchToRoute(Request$request)    {$route =$this->findRoute($request);$request->setRouteResolver(function()use($route)        {return$route;        });$this->events->fire('router.matched', [$route,$request]);$response =$this->callRouteBefore($route,$request);if (is_null($response))        {// 只看这一行,还是调度文件$response =$this->runRouteWithinStack($route,$request            );        }$response =$this->prepareResponse($request,$response);$this->callRouteAfter($route,$request,$response);return$response;    }//干货来了protectedfunctionrunRouteWithinStack(Route$route, Request$request)    {// 取得routes.php里面的Middleware节点$middleware =$this->gatherRouteMiddlewares($route);//这个有点眼熟return (new Pipeline($this->container))                        ->send($request)//执行上述的中间件                        ->through($middleware)                        ->then(function($request)use($route)                        {//不容易啊,终于到Controller类了return$this->prepareResponse($request,//run控制器$route->run($request)                            );                        });    }publicfunctionrun(Request$request)    {$this->container =$this->container ?:new Container;try        {if ( ! is_string($this->action['uses']))return$this->runCallable($request);if ($this->customDispatcherIsBound())//实际上是运行了这行return$this->runWithCustomDispatcher($request);//其实我是直接想运行这行return$this->runController($request);        }catch (HttpResponseException$e)        {return$e->getResponse();        }    }//继续调度,最终调度到.../Illuminate/Routing/ControllerDispatcher.php文件的dispatch方法protectedfunctionrunWithCustomDispatcher(Request$request)    {list($class,$method) = explode('@',$this->action['uses']);$dispatcher =$this->container->make('illuminate.route.dispatcher');return$dispatcher->dispatch($this,$request,$class,$method);

}

文件清单…/Illuminate/Routing/ControllerDispatcher.php

publicfunctiondispatch(Route$route, Request$request,$controller,$method)    {$instance =$this->makeController($controller);$this->assignAfter($instance,$route,$request,$method);$response =$this->before($instance,$route,$request,$method);if (is_null($response))        {//还要调度$response =$this->callWithinStack($instance,$route,$request,$method            );        }return$response;    }protectedfunctioncallWithinStack($instance,$route,$request,$method)    {//又是Middleware......有没有忘记,官方文档里面Middleware可以加在控制器的构造函数中!!没错,这个Middleware就是在控制器里面申明的$middleware =$this->getMiddleware($instance,$method);//又是这个,眼熟吧return (new Pipeline($this->container))                    ->send($request)//再次运行Middleware                    ->through($middleware)                    ->then(function($request)use($instance,$route,$method)                    {                            运行控制器,返回结果return$this->call($instance,$route,$method);

});

}

分类:PHP

好文要顶关注我收藏该文

lpfuture

关注 - 5

粉丝 - 6

+加关注

1

0

HTTP / Console 内核

接下来,传入的请求会被发送给 HTTP 内核或者 console 内核,这根据进入应用的请求的类型而定。这两个内核服务是所有请求都经过的中枢。让我们现在只关注位于app/Http/Kernel.php的 HTTP 内核。

HTTP 内核继承自Illuminate\Foundation\Http\Kernel类,它定义了一个bootstrappers数组,数组中的类在请求真正执行前进行前置执行。 这些引导程序配置了错误处理,日志记录,检测应用程序环境,以及其他在请求被处理前需要完成的工作。

HTTP 内核同时定义了一个 HTTP中间件列表,所有的请求必须在处理前通过这些中间件,这些中间件处理HTTP session的读写,判断应用是否在维护模式,验证 CSRF token等等。

HTTP 内核的标志性handle方法是相当简单的:接收一个Request并返回一个Response。你可以把内核想成一个代表你应用的大黑盒子。给它喂 HTTP 请求然后它就会吐给你 HTTP 响应。

服务提供者

在内核引导启动的过程中最重要的动作之一就是载入服务提供者到你的应用。所有的服务提供者都配置在config/app.php文件中的providers数组中。 首先,所有提供者的register方法会被调用,接下来,一旦所有提供者注册完成,boot方法将会被调用。

服务提供者负责引导启动框架的全部各种组件,例如数据库、队列、验证器以及路由组件。因为这些组件引导和配置了框架的各种功能,所以服务提供者是整个 Laravel 启动过程中最为重要的部分。

分发请求

一旦应用完成引导和所有服务提供者都注册完成,Request将会移交给路由进行分发。路由将分发请求给一个路由或控制器,同时运行路由指定的中间件。

聚焦服务提供者

服务提供者是 Laravel 应用的真正关键部分,应用实例被创建后,服务提供者就会被注册完成,并将请求传递给应用进行处理,真的就是这么简单!

了解 Laravel 是怎样通过服务提供者构建和引导一个稳定的应用是非常有价值的,当然,应用的默认服务提供者都存放在app/Providers目录中。

在新创建的应用中,AppServiceProvider文件中方法实现都是空的。这个提供者是你添加应用专属的引导和服务的最佳位置,当然的,对于大型应用你可能希望创建几个服务提供者,每个都具有粒度更精细的引导。

译者署名

用户名头像职能签名

@麦索

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • 过去做事情急,什么东西拿起来就用,不喜欢进行系统性的学习,造成在使用过程中的错误和低效,现在感觉自己耐心多了,用之...
    马文Marvin阅读 1,915评论 0 10
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 校园失物招领平台开发 ——基于laravel框架构建最小内容管理系统 摘要 ​ 针对目前大学校园人口密度大、人群活...
    蓝莲花xzsky阅读 6,084评论 8 55
  • 最近在和同学参与一个创业项目,用到了laravel,仔细研究了一下,发现laravel封装了很多开箱即用的方法,通...
    MakingChoice阅读 3,275评论 0 0
  • 由于工作的原因,每天中午都走过深圳北站的西广场吃午餐,总能看到游客以车站穹顶的“深圳北站”为背景自拍或者摆拍,有的...
    河之流阅读 279评论 2 11