淺談Laravel中的設計模式(三) Container 容器

寫程式的趙童鞋發表於2018-10-22

閱讀時長:5分鐘

技術預備:熟悉Laravel的使用

容器(Container)

一、什麼是容器呢?

容器這個詞估計使用過Laravel的童鞋們肯定不陌生了,但是日常業務開發好像都沒見過它,我們今天就來看看他到底是幹什麼用的,本篇使用Laravel的精簡版Lumen進行舉例。

首先他出現在哪裡呢?

淺談Laravel中的設計模式(三) Container 容器

我們可以從入口檔案找到他,就是這個$app,那麼這個$app到底是什麼?我們繼續深入看看

淺談Laravel中的設計模式(三) Container 容器
淺談Laravel中的設計模式(三) Container 容器

在app.php資料夾中可以看到,這個$app就是Laravel\Lumen\Application::class,而這個類繼承了Container類,所以說Application類就是Laravel中的容器了。

“趙童鞋,究竟什麼是容器呢?"

Laravel中的容器其實就是整個框架的核心,在上圖的index.php中可以看到,一個Request進來後,index.php其實只是呼叫了$app->run()方法。

之後的URL解析、中介軟體處理、依賴注入,直到請求進入業務方法裡,通通都是容器在進行處理。

二、容器是怎麼運作的呢?

像上述所說,Laravel框架中的大部分功能都是在容器中實現的,而最常用的功能就有服務提供者。

我們這裡就通過呼叫DB的Facade類來說明一下容器中的服務提供者是怎麼運作的。

淺談Laravel中的設計模式(三) Container 容器

首先可以看到,在Application中,"db" 繫結了registerDatabaseBindings()這個方法。

淺談Laravel中的設計模式(三) Container 容器

registerDatabaseBindings()方法中,使用了框架提供的singleton()註冊了一個關聯“db”的匿名函式,而這個匿名函式就是“db”的解析器。

在前面的篇章我們講到,當我們通過靜態呼叫DB類的時候,Laravel的Facade模式就通過呼叫resolveFacadeInstance()去容器中解析出“db”的實際物件。

淺談Laravel中的設計模式(三) Container 容器
可以看到,裡面的實際操作是使用了static::$app[$name]的寫法去獲取。

因為Laravel中的Container實現了ArrayAccess,所以實際呼叫會進入到Container的offsetGet()方法中,也就是進入了make()方法,而因為容器的實際物件是Application類,所以會先進入Application的make()方法。

淺談Laravel中的設計模式(三) Container 容器

淺談Laravel中的設計模式(三) Container 容器

在make方法中,終於出現了前面說到的$availableBindings,也就是說,在這裡會呼叫前面的registerDatabaseBindings()方法,註冊“db”的解析器。再進行呼叫父類,也就是Container的make()方法。

淺談Laravel中的設計模式(三) Container 容器

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

(不得不說,當初第一次看框架程式碼時我也被繞暈了,習慣就好)

淺談Laravel中的設計模式(三) Container 容器

resolve()這裡,容器會先去$this->instances中查詢,也就是一個用於存放已例項化的物件的陣列。

當獲取不到的時候,就會通過$this->getConcrete()獲取到我們前面註冊的“db”的解析器,也就是呼叫文章最前面registerDatabaseBindings()中的匿名函式,獲取到“db”的例項,最終返回給前面的DB靜態呼叫。

(至於匿名函式解析器是怎麼工作的,感興趣的童鞋可以去看看官方文件的loadComponent、register流程,親自去看一遍原始碼印象更深刻)

三、容器有什麼用呢?

通過上面的描述,我們可以知道容器中是有一個陣列instances[]儲存著已例項化了的物件的,也就是單例模式。

而沒有例項化的物件也是有著類似於解析器之類的關聯機制。

這種做法最大的好處就是可以減少物件生成的開銷,例如某個介面需要使用到Redis和DB,那麼框架就會去呼叫解析器將這兩個物件解析出來,並且儲存在陣列中以便於後續的邏輯中進行復用。

而當某個介面不需要Redis和DB的時候,就可以節省下這兩個物件的開銷,並不需要修改一句程式碼。

四、結語

本次的淺談容器到這裡就結束了,如果覺得被繞暈了的話,說明真的認真看了o( ̄▽ ̄)d。

千萬別灰心,親自去跟著原始碼走一趟,這種被繞暈的感覺就會慢慢消失了。

----- End -----

更多好文

請掃描下面二維碼

歡迎關注~

淺談Laravel中的設計模式(三) Container 容器

相關文章