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实例调用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
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文件中方法实现都是空的。这个提供者是你添加应用专属的引导和服务的最佳位置,当然的,对于大型应用你可能希望创建几个服务提供者,每个都具有粒度更精细的引导。
译者署名
用户名头像职能签名