淺談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 -----

更多好文

請掃描下面二維碼

歡迎關注~

相關文章
相關標籤/搜索