從百草園到三味書屋 (四)服務提供者

一句話兒發表於2020-02-10
  1. 一個Laravel服務提供者就是一個用來進行IoC繫結的類。

  2. 事實上,Laravel有好幾十個服務提供者,用於管理框架核心元件的容器繫結。

  3. 幾乎框架裡每一個元件的IoC繫結都是靠服務提供者來做的。

  4. 你可以在app/config/app.php這個檔案裡檢視目前有哪些服務提供者。

  1. 一個服務提供者必須有一個register方法。你可以在這個方法裡寫IoC繫結。

  2. 當一個請求發過來,程式框架剛啟動時,所有在你配置檔案裡的服務提供者的register方法就會被呼叫。

    3.這在程式週期的很早的地方就會執行,所以在你自己的引導程式碼(比如那些在start目錄裡的檔案)裡所有的服務已經準備好了。

  1. 永遠不要在register方法裡面使用任何服務。
  2. 該方法只是用來進行IoC繫結的地方。
  3. 所有關於繫結類後續的判斷、互動都要在boot方法裡進行。
  1. 並非在你配置檔案中的providers陣列裡的所有提供者在每次請求都會被例項化。
  2. 否則會對效能不利,尤其是這個服務的功能用不到的情況下。
  3. 比如,QueueServiceProvider服務就不是每次都用得到。

為了達到只例項化需要的服務的提供者,Laravel生成了“服務清單”並且儲存在了app/storage/meta目錄下。這份清單列出了應用裡所有的服務提供者,包括容器繫結的名字也記錄了。這樣,當應用想讓容器取出一個名為queue的繫結時,Laravel知道需要先例項化並執行QueueServiceProvider因為在服務清單裡記錄著該服務提供者能提供queue的繫結。如此這般框架就能夠延遲載入每個請求需要的服務了,效能大大提高。

你應用的“啟動”檔案都儲存在app/start目錄下。根據不同的請求入口,系統會載入不同的啟動檔案。在全域性的start.php檔案載入後,系統會根據執行環境的不同來載入不同的啟動檔案。 此外,在執行命令列程式時,artisan.php檔案會被載入。

也許我們的應用正在使用Pusher 來為客戶推送訊息。為了將我們的應用和Pusher解耦,我們要定義EventPusherInterface介面和對應的實現類PusherEventPusher。這樣在需求變化或應用改進時,我們就可以隨時輕鬆的改變推送服務提供商。

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...
    }
}

//接下來我們建立一個EventPusherServiceProvider:
use Illuminate\Support\ServiceProvider;
class EventPusherServiceProvider extends ServiceProvider {
    public function register()
    {
        $this->app->singleton('PusherSdk', function()
        {
            return new PusherSdk('app-key', 'secret-key');
        }
        $this->app->singleton('EventPusherInterface', 'PusherEventPusher');
    }
}

很好! 我們對事件推送進行了清晰的抽象,同時我們也有了一個很不錯的地方進行註冊、繫結其他相關的東西到容器裡。最後一步只需要將EventPusherServiceProvider寫入app/config/app.php檔案內的providers陣列裡就可以了。現在這個應用裡的EventPusherInterface已經被繫結到了正確的實現類上。

用不用單例可以這樣來考慮:如果在一次請求週期中該類只需要有一個例項,就使用singleton;否則就使用bind。

在所有服務提供者都註冊以後,他們就進入了“啟動”過程。該過程會觸發每個服務提供者的boot方法。這裡會發生一種常見的錯誤用法:在register方法裡面呼叫其他的服務。由於在register方法裡我們不能保證所有其他服務都已經被載入,所以在該方法裡呼叫別的服務有可能會出錯。所以如果你想在服務提供者裡呼叫別的服務,請在boot方法裡做這種事兒。register方法只能進行容器註冊。

在啟動方法裡面,你想做什麼都可以:註冊事件監聽,引入路由檔案,註冊過濾器,或者其他你能想象到的事兒。再強調一下,要發揮服務提供者的管理功能。可能你想將相關的多個事件監聽歸為一組?將他們放到一個服務提供者的boot方法裡,這會很管用的!或者你也可以引入單獨的“events”、“routes”PHP檔案:

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

理解Laravel核心的最好方法是去讀它的核心服務原始碼。如果你對這些服務的原始碼、容器註冊等都很熟悉,那麼你對Laravel是如何工作的將會有十分深刻的理解。

大部分的服務提供者是延遲載入的,意味著並非所有請求都會呼叫到他們;然而有一些很基礎的服務是每一次請求都會被載入的,比如FilesystemServiceProvide和ExceptionServiceProvider。有人會說核心服務提供者和應用程式容器就是Laravel。Laravel 其實是將這麼多不同部分聯絡起來,形成一個單一的、內聚的整體的這麼一個機制。拿建築來比喻,那些服務提供者就是框架的預製模組。

原文連結:https://my.oschina.net/zgldh?tab=newest&am...

本作品採用《CC 協議》,轉載必須註明作者和本文連結
寫的不好,就當是整理下思緒吧。

相關文章