Laravel深入學習4 – 服務提供器

laravel發表於2019-02-16

宣告:本文並非博主原創,而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當然也不是原汁原味的翻譯,能保證90%的原汁性,另外因為是理解翻譯,肯定會有錯誤的地方,歡迎指正。

歡迎轉載,轉載請註明出處,謝謝!

服務提供器

啟動引導

Laravel服務提供器是往IoC容器中繫結服務的類。事實上,框架核心就是由很多這樣的服務提供器驅動管理著容器中繫結的各種資源。基本上框架中的所有元件都是以這種使用提供器注入資源到容器的方式進行註冊的。從專案檔案app/config/app.php中的providers陣列中可以瀏覽到當前專案使用的提供器列表。

一個服務提供器必須包含至少一種方法:registerregister方法中實現了類繫結到容器的邏輯。當使用者發起一個請求時,框架啟動,配置檔案中定義的服務提供器的register方法會被執行。這在Laravel執行生命週期的早期就會觸發,所以,當你的啟動檔案、比如start目錄中的檔案載入之後,這些服務啟動器就已經可用了。

註冊 vs 啟動

不要試圖在register方法中使用提供器服務。他只是為了將物件繫結到容器中來使用的。所有關於繫結類的後續操作都應在boot方法中完成的。

一些通過Composer安裝的第三方類庫,都是通過服務提供器進行注入的。類庫的安裝說明會明確的讓你在配置檔案中通過向providers陣列方法新增配置來使用他們的服務。服務提供器一旦被註冊,就可被用於程式的各個地方。

類庫服務提供

不是所有的類庫都需要服務提供器。實際上,沒有類庫需要它,服務提供器的作用通常被用來啟動元件並使之馬上能被使用。他其實就是一個方便我們啟動引導程式碼類庫繫結到容器的工具。

延遲提供器

在每次請求中,不是所有的列在providers配置陣列中的服務都會被例項化。這對在效能其實是不利的,特別是當他們已經被註冊,但是專案中又沒有使用到它,這就是一種浪費。比如,QueueServiceProvider服務,只有在那些利用了佇列的請求中才會使用到。

為了在請求中,只例項化那些必須的服務,laravel生成了一個“伺服器清單”並儲存在app/storage/meta目錄中。清單中列出了所有應用可能需要用到的服務,也記錄了容器需要繫結的類庫的名稱。當應用中需要使用queue服務時,Laravel知道如何從清單中載入並例項化QueueServiceProvider。這種延遲載入服務的方式,極大的提高了整體的效能。

清單的生成

當在providers陣列中新增資料時,Laravel會在下一次請求時自動重新生成清單。

有時間的話,還是要好好看看這個清單的,他對你除錯延遲載入服務是非常有幫助的。

組織器

想使用Laravel構建出一個高擴充套件性良好的應用,那麼就有必要學習並將服務提供器作為一種組織工具來管理我們的程式碼。當向IoC容器注入大量類時,程式碼都是雜亂的放到app/start檔案中來操作的。我們可以使用服務提供器註冊服務的方式來代替上面的方式。

萬物伊始

應用所有“啟動檔案”都存放在app/start目錄下的。在請求達到應用時,根據請求型別的不同載入相應的“引導”檔案。啟動檔案根據當前環境在start.php之後被載入。例如:artisan.php只在終端命令列模式下被載入。

如下示例。我們的應用可能是在使用Pusher4來進行向使用者的訊息推送。為了將Pusher進行解耦,這裡須要建立一個EventPusherInterface介面和一個PusherEventPuser實現。當需求變更時,我們就能很容易的改變訊息服務商。

interface EventPusherInterface{
    public function push($message, array $data = array());
}

class PusherEventPusher implements EventPusherInterface{
    public function __construct(PusherSdk $pusher)
    {
        $this->pusher = $pusher;
    }
    public function push($message, array $data = array())
    {
        // Push message via the Pusher SDK...
    }
}

下面,我們建立一個EventPuserServiceProvider

use IlluminateSupportServiceProvider;

class EventPusherServiceProvider extends ServiceProvider {
    public function register()
    {
        $this->app->singleton(`PusherSdk`, function()
        {
            return new PusherSdk(`app-key`, `secret-key`);
        }

        $this->app->singleton(`EventPusherInterface`, `PusherEventPusher`);
    }
}

贊!我們對時間推送進行了清晰的抽象。同時我們還有一個不錯的地方將服務註冊繫結到容器中。我們只須要在app/config/app.phpprovider陣列中新增EventPusherServiceProvider即可。在接下來的應用中,任何控制器和類都能使用這個注入的服務。

是否須要單例?

我們總需要合適使用bindsingleton。記住一點,一次請求只用一次用singleton,否則用bind

注意:服務提供器的$app變數來自ServiceProvider類中。他是IlluminateFoundationApplication的例項化物件,繼承自Container類,所以可以上面一樣呼叫容器中的各種方法。如果你喜歡App這種門面模式,也可以:

App::singleton(`EventPusherInterface`, `PusherEventPusher`);

當然,服務提供器的功能不止於此,我們也可以註冊雲端儲存、資料庫訪問、自定義模版引擎如Twig等型別的服務。他就是你應用中的引導和管理工具,如此而已。

所以,盡情建立屬於你自己的服務提供器吧。這不需要你非得釋出個程式碼包,只是個管理管理工具,來方便應用載入各種專案須要的元件。

啟動服務

當所有的服務提供器註冊之後,他們就變成了“已啟動”狀態。每個提供器中的boot方法都會觸發。我們通常會犯這樣一種錯誤,就是在register方法試圖去呼叫其他服務。而此時並不能保證所有的服務均已被載入,服務很可能在當前是不可用的,這就會出現錯誤。因此,我們應該總是在boot方法中去呼叫其他服務。register方法僅僅是用來將服務註冊到容器中。

在boot方法中,你可以做任何事情:註冊時間監聽器,載入路由檔案,註冊過濾器,以及任何你能想到的東西。再次提示,把服務提供器作為一種組織工具來使用。也許你希望把一些監聽事件組織起來?把他們放到boot方法來實現就是一個很好的方法!或者,你也可以引入一個PHP的“事件”或者“路由”檔案:

public function boot()
{
    require_once __DIR__.`/events.php`;
    require_once __DIR__.`/routes.php`;
}

現在我們已經學習了依賴注入和利用服務提供器來組織專案,我們有了使用Laravel建立可維護、可測試程式的應用架構的強大基礎。下面,我們繼續深入學習Laravel本身是如何使用服務提供器,框架如何在這個引擎下工作!

別被這些框框束縛了自己

記住,不要老想著只有程式包才能使用服務提供器。要將他作為我們組織服務的好工具。

服務核心

你應該已經注意到app配置檔案中已經有很多服務了。每一個都會啟動框架核心的各個部分。比如,MigrationServiceProvider負責載入資料庫遷移的類庫,以及載入Artisan命令;EventServiceProvider負責註冊事件排程類。一些服務相對比較負責,但都是負責啟動框架核心的某一部分。

約一約這些服務們

理解這些核心服務最好的方法還是去讀下原始碼。如果能對這些服務的原始碼,和容器的注入非常熟悉,那麼Laravel的工作原理也就會變的非常明瞭了。

大部分的服務都是延遲載入的,並非所有請求都會呼叫他們;然而框架基本的部分像FilesystemServiceProviderExceptionServiceProvider還是會隨請求一起啟動的。有些人會說核心服務和容器_就是_Laravel。Laravel就是將所有不同的部分組合成一個單一,內聚的整體。這些服務就是框架這棟大廈的骨架。

再囉嗦一次,想了解Laravel如何工作,還是得看原始碼,看看框架如何驅動這些核心服務。能明白這些服務如何組織的一塊,這些服務如何實現本身的功能。深諳這些之後,也許你也能為Laravel做出自己的貢獻!

相關文章