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 接下来会带来哪些丰富的体验呢?
欢迎关注下一章!
关于 LearnKu
推荐文章: