Laravel 执行流程(六)之 启动 kernel
备注:纯手打的学习笔记,如有错误之处请指正,谢谢。希望大家学的开心!
辛苦分享,能赞的就赞一个吧,也欢迎大家交流互动
前两章初步认识了 bind
和 make
使我们明白生成一个实例的步骤,接下来,我们要认识 kernel
,这是与用户交互的关键,咱们打开入口文件截图如下:
咱们根据这行代码和这个参数,具体来捋一捋 $kernel
是如何生成的,也当复习。
$app
这个不用解释即 application
类,之前说的 make
方法是位于 container
类中,其实 application
类中也有 make
方法,截图如下:
我们现在还不知道具体的用意在哪,不过我们看见了内部调用了父类( container
)的 make
方法,所以执行过程是先通过子类的 make
调用到父类的 make
,根据参数咱们继续往下看,这里只传了一个Illuminate\Contracts\Http\Kernel
参数,所以 $parameters
可以无视了。
在继续分析父类 make
方法之前,我们要知道,在 bootstrap/app.php
里进行了3次 singleton
操作, singleton
前面也说过,也就是调用 bind
方法,截图如下:
我们看见第一个 singleton
一目了然,对应了我们今天要说的类,不过后面多了一个参数(app\Http\Kernel
),这个参数原型名字是 $concrete
,即具体物。
了解以上这些,我们才正式分析父类的 make
方法:
Make
方法前一章单独说过了,所以略过没有执行到的代码。
这里我们知道,Illuminate\Contracts\Http\Kernel
还没有生成实例,只是绑定了而已,说到绑定,不知道大家还记得 bind
方法是怎么执行的吗?其中有一步是判断如果 $concrete
这个参数不是一个闭包的,则调用 getClosure
方法来强制生成一个闭包给 $concrete
,截图如下:
这里注意,$method
最终得到 make
,3元运算比较了2个参数,我们知道参数不一样,所以取后者,注释部分是我调试的记录,大家可参照测试。咱们把 getClosure
先截图记录,一会用到方便看,咱们继续看 container
类的 make
方法。
我们知道这个方法只能返回2种参数,一个是闭包对象,一个字符参数,这里 $concrete
自然是得到一个闭包对象,因为已经绑定过了。
接着直接执行了 build
方法,咱们看 build
方法内的关键代码:
嗯看到这里,我们上一章也说过,一个闭包的调用,这里需要跳回 getClosure
继续分析了:
$concrete($this, $parameters)
这里是传了一个 this
参数,即 application
类,所以 $c=application
类,那结合刚才说 getClosure
方法,这里闭包内部应该是执行一个 $c->make($concrete)
逻辑,注意参数 $concrete
是第一次传的 app\Http\Kernel
字符串;那更直接一点,代码其实是这样 application->make(‘app\Http\Kernel’)
。
从 make(‘Illuminate\Contracts\Http\Kernel’)
又转换到 make(‘app\Http\Kernel’)
,我们现在只需要知道这个顺序。
好,那再一次去看 make
如何实例化这个 app\Http\Kernel
类的,这次应该有不同的收获哟。
再次执行到 getConcrete
方法,我们说了要么是返回一个闭包对象,要么就是一个字符串,前面都是返回的闭包,而这次呢?转到 getConcrete
相关代码:
这次应该执行里面,app\Http\Kernel
没有绑定过,而 missingLeadingSlash
我们前一章说过:
这里,逻辑不成立,不用多解释了吧,所以直接返回 app\Http\Kernel
字符串。
嗯哼,现在得到一个字符串了,不再是闭包对象了,应该有新的玩意可以学习,咱们继续往下:
isBuildable
判断成立,然后继续执行 build
方法。
前一章留下反射的伏笔,终于可以接触了,忘了反射的看第二章有详细例子。
Build
方法逻辑顺序:
先是我们最熟悉的闭包实例判断,我们这里只是一个字符串,所以不成立,再见。
然后 new
了一个反射类
呵呵,开始给 app\Http\Kernel
动手术了。
先是来了个 isInstantiable
判断,PHP
官网解释:
嗯哼,只要你不能实例化,直接抛错。
接下来又学到一个新数组
绑定栈,百度百科科普一下:
额,app\Http\Kernel
进入了栈结构了,废话!
紧接着又继续用到反射方法 getConstructor
,继续 PHP
官网:
在看下官方给的示例便于理解:
这下清楚了,如果反射不存在的话就返回一个 null
。
接下来也是一个 is_null
判断
注释很明了,不需要多余的工作,先是出栈,弹出 $concrete
,然后直接返回对象实例。
这里 app\Http\Kernel
继承了父类 Illuminate\Foundation\Http\Kernel
,并且有构造函数,这里先发一下构造函数原型,以便后面更容易理解:
那么现在我们还得继续往下分析,发一下 $constructor
调试截图,更清晰一点:
OK,那么现在 $constructor
是一个 ReflectionMethod
对象,这个反射方法对象我们在第二章也演示过,是针对类的方法。
紧接着
getParameters
方法示例:
一环扣一环,返回值依然是一个新对象,不过是针对参数。
调试截图:
嗯,确实匹配构造函数的参数,没什么大问题,每一个参数即是一个 ReflectionParameter
对象。
嗯哼,接下来也很关键:
keyParametersByArgument
的逻辑还没有实现,所以这里也略过,直接看 getDependencies
方法。
首先 $parameters
这里为空,$dependencies
为一个数组,每一个单元是一个 ReflectionParameter
对象。
这里也把依赖说的很直接了,变量名直接是 dependencies
,也就是这些参数都是依赖。看看 getDependencies
是如何去解决这些依赖的。
其实只要咱们把新学的知识记熟的话,看起来 so easy。
首先声明一个数组变量,而 parameters
数组目前为止有2个单元,就是这2个参数
接着循环,前2层 if
都可以略过,没用到,第三层则调用了 resolveClass
方法。
对了,这个地方要特别提一下
这是 ReflectionParameter
对象的方法,用官网的语言还搞不明白,我就简答举个例子,第一个循环的$parameter
的参数是 app
对不,然后 $app
参数限定了必须继承于 Application
类,而 Application
类是 use
过的,如图:
而 getClass
方法最后的结果是这样:
返回了一个 ReflectionClass
对象,这样应该好理解些。
或者给你们一个传送门:
OK,现在 dependency
变量是一个反射对象了,我们继续看下 resolveClass
又干了些什么?
好,我们先简化一下
即 $this->make(‘Illuminate\Contracts\Foundation\Application’)
Make
就不多说了,因为 application
类早在一开始就实例化好了,因为判断了 instances
数组,直接返回,至于下面的一个异常具体干什么,还没用到,就此略过。
我们回到build方法上来
OK,现在 $instances
是获得一个数组列表,分别有2个单元,分别对应了2个对象Illuminate\Foundation\Application
和 Illuminate\Routing\Router
。
接着出栈
最后很关键的地方来了
这个简单了吧,正好对应构造函数
嗯哼,原来是这样解决的依赖关系,真尼玛有套路啊。。
好 build
方法咱们算是理解了那么一些了。
返回到 make
方法
现在 $object
其实就是 app\Http\Kernel
类实例!
剩下的前一章都说了,没用到的依然没用到。
到了总结时刻
本章关键点在于 build
方法利用反射解决依赖关系那里,还有也进一步学习了 getClosure
方法内部逻辑,废话说多了不如自己多看多思考,我觉得反射部分大家可以深入思考一下,或许这个特性能使我们在 OOP
路上更上一层楼,我也还需要在消化消化,至此,启动完成,那么 kernel
接下来会带来哪些丰富的体验呢?
欢迎关注下一章!