浅谈Laravel中的设计模式(三) Container 容器

阅读时长:5分钟php

技术预备:熟悉Laravel的使用数组

容器(Container)

1、什么是容器呢?

容器这个词估计使用过Laravel的童鞋们确定不陌生了,可是平常业务开发好像都没见过它,咱们今天就来看看他究竟是干什么用的,本篇使用Laravel的精简版Lumen进行举例。app

首先他出如今哪里呢?框架

咱们能够从入口文件找到他,就是这个$app,那么这个$app究竟是什么?咱们继续深刻看看函数

在app.php文件夹中能够看到,这个$app就是Laravel\Lumen\Application::class,而这个类继承了Container类,因此说Application类就是Laravel中的容器了。this

“赵童鞋,究竟什么是容器呢?"3d

Laravel中的容器其实就是整个框架的核心,在上图的index.php中能够看到,一个Request进来后,index.php其实只是调用了$app->run()方法。code

以后的URL解析、中间件处理、依赖注入,直到请求进入业务方法里,统统都是容器在进行处理。cdn

2、容器是怎么运做的呢?

像上述所说,Laravel框架中的大部分功能都是在容器中实现的,而最经常使用的功能就有服务提供者。中间件

咱们这里就经过调用DB的Facade类来讲明一下容器中的服务提供者是怎么运做的。

首先能够看到,在Application中,"db" 绑定了registerDatabaseBindings()这个方法。

registerDatabaseBindings()方法中,使用了框架提供的singleton()注册了一个关联“db”的匿名函数,而这个匿名函数就是“db”的解析器。

在前面的篇章咱们讲到,当咱们经过静态调用DB类的时候,Laravel的Facade模式就经过调用resolveFacadeInstance()去容器中解析出“db”的实际对象。

能够看到,里面的实际操做是使用了 static::$app[$name]的写法去获取。

由于Laravel中的Container实现了ArrayAccess,因此实际调用会进入到Container的offsetGet()方法中,也就是进入了make()方法,而由于容器的实际对象是Application类,因此会先进入Application的make()方法。

在make方法中,终于出现了前面说到的$availableBindings,也就是说,在这里会调用前面的registerDatabaseBindings()方法,注册“db”的解析器。再进行调用父类,也就是Container的make()方法。

而make()方法又跳进了resolve()中。

(不得不说,当初第一次看框架代码时我也被绕晕了,习惯就好)

resolve()这里,容器会先去$this->instances中查找,也就是一个用于存放已实例化的对象的数组。

当获取不到的时候,就会经过$this->getConcrete()获取到咱们前面注册的“db”的解析器,也就是调用文章最前面registerDatabaseBindings()中的匿名函数,获取到“db”的实例,最终返回给前面的DB静态调用。

(至于匿名函数解析器是怎么工做的,感兴趣的童鞋能够去看看官方文档的loadComponent、register流程,亲自去看一遍源码印象更深入)

3、容器有什么用呢?

经过上面的描述,咱们能够知道容器中是有一个数组instances[]保存着已实例化了的对象的,也就是单例模式。

而没有实例化的对象也是有着相似于解析器之类的关联机制。

这种作法最大的好处就是能够减小对象生成的开销,例如某个接口须要使用到Redis和DB,那么框架就会去调用解析器将这两个对象解析出来,而且保存在数组中以便于后续的逻辑中进行复用。

而当某个接口不须要Redis和DB的时候,就能够节省下这两个对象的开销,并不须要修改一句代码。

4、结语

本次的浅谈容器到这里就结束了,若是以为被绕晕了的话,说明真的认真看了o( ̄▽ ̄)d。

千万别灰心,亲自去跟着源码走一趟,这种被绕晕的感受就会慢慢消失了。

----- End -----

更多好文

请扫描下面二维码

欢迎关注~

相关文章
相关标签/搜索