鍍金池/ 教程/ PHP/ 服務(wù)提供者
門面
Laravel Homestead
安裝及配置
測試
HTTP 中間件
加密
升級(jí)指南
幫助函數(shù)
應(yīng)用目錄結(jié)構(gòu)
集合
新手入門指南-簡單任務(wù)管理系統(tǒng)
任務(wù)調(diào)度
查詢構(gòu)建器
視圖
驗(yàn)證
Laravel Cashier(訂購&支付&發(fā)票)
本地化
隊(duì)列
調(diào)整器
分頁
文件系統(tǒng)/云存儲(chǔ)
貢獻(xiàn)代碼
哈希
HTTP 控制器
緩存
遷移
HTTP 請求
Laravel Elixir
發(fā)行版本說明
Envoy 任務(wù)運(yùn)行器(SSH任務(wù))
序列化
Session
起步
帶用戶功能的任務(wù)管理系統(tǒng)
起步
用戶授權(quán)
郵件
事件
填充數(shù)據(jù)
HTTP 路由
服務(wù)提供者
Blade 模板引擎
包開發(fā)
用戶認(rèn)證
Artisan 控制臺(tái)
HTTP 響應(yīng)
集合
服務(wù)容器
關(guān)聯(lián)關(guān)系
一次請求的生命周期
契約
Redis
錯(cuò)誤&日志

服務(wù)提供者

1、簡介

服務(wù)提供者是所有 Laravel 應(yīng)用啟動(dòng)的中心,你自己的應(yīng)用以及所有 Laravel 的核心服務(wù)都是通過服務(wù)提供者啟動(dòng)。

但是,我們所謂的”啟動(dòng)“指的是什么?通常,這意味著注冊事物,包括注冊服務(wù)容器綁定、時(shí)間監(jiān)聽器、中間件甚至路由。服務(wù)提供者是應(yīng)用配置的中心。

如果你打開 Laravel 自帶的 config/app.php 文件,將會(huì)看到一個(gè) providers 數(shù)組,這里就是應(yīng)用所要加載的所有服務(wù)提供者類,當(dāng)然,其中很多是延遲加載的,也就是說不是每次請求都會(huì)被加載,只有真的用到它們的時(shí)候才會(huì)加載。

本章里你將會(huì)學(xué)習(xí)如何編寫自己的服務(wù)提供者并在 Laravel 應(yīng)用中注冊它們。

2、編寫服務(wù)提供者

所有的服務(wù)提供者繼承自 Illuminate\Support\ServiceProvider 類。繼承該抽象類要求至少在服務(wù)提供者中定義一個(gè)方法:register。在 register 方法內(nèi),你唯一要做的事情就是綁事物到服務(wù)容器,不要嘗試在其中注冊任何時(shí)間監(jiān)聽器,路由或者任何其它功能。

通過 Artisan 命令 make:provider 可以簡單生成一個(gè)新的提供者:

php artisan make:provider RiakServiceProvider

2.1 register 方法

正如前面所提到的,在register 方法中只綁定事物到服務(wù)容器,而不要做其他事情,否則話,一不小心就能用到一個(gè)尚未被加載的服務(wù)提供者提供的服務(wù)。

現(xiàn)在讓我們來看看一個(gè)基本的服務(wù)提供者長什么樣:

<?php

namespace App\Providers;

use Riak\Connection;
use Illuminate\Support\ServiceProvider;

class RiakServiceProvider extends ServiceProvider{
    /**
     * 在容器中注冊綁定.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('Riak\Contracts\Connection', function ($app) {
            return new Connection(config('riak'));
        });
    }
}

該服務(wù)提供者只定義了一個(gè) register方法,并使用該方法在服務(wù)容器中定義了一個(gè) Riak\Contracts\Connection的實(shí)現(xiàn)。如果你不太理解服務(wù)容器是怎么工作的,查看其文檔。

2.2 boot 方法

如果我們想要在服務(wù)提供者中注冊視圖 composer 該怎么做?這就要用到 boot方法了。該方法在所有服務(wù)提供者被注冊以后才會(huì)被調(diào)用,這就是說我們可以在其中訪問框架已注冊的所有其它服務(wù):

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class EventServiceProvider extends ServiceProvider{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        view()->composer('view', function () {
            //
        });
    }

    /**
     * 在容器中注冊綁定.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

2.2.1 boot 方法的依賴注入

我們可以在boot方法中類型提示依賴,服務(wù)容器會(huì)自動(dòng)注冊你所需要的依賴:

use Illuminate\Contracts\Routing\ResponseFactory;

public function boot(ResponseFactory $factory){
    $factory->macro('caps', function ($value) {
        //
    });
}

3、注冊服務(wù)提供者

所有服務(wù)提供者都是通過配置文件 config/app.php中進(jìn)行注冊,該文件包含了一個(gè)列出所有服務(wù)提供者名字的providers數(shù)組,默認(rèn)情況下,其中列出了所有核心服務(wù)提供者,這些服務(wù)提供者啟動(dòng) Laravel 核心組件,比如郵件、隊(duì)列、緩存等等。

要注冊你自己的服務(wù)提供者,只需要將其加到該數(shù)組中即可:

use Illuminate\Contracts\Routing\ResponseFactory;

public function boot(ResponseFactory $factory){
    $factory->macro('caps', function ($value) {
        //
    });
}

4、延遲加載服務(wù)提供者

如果你的提供者僅僅只是在服務(wù)容器中注冊綁定,你可以選在延遲加載該綁定直到注冊綁定真的需要時(shí)再加載,延遲加載這樣的一個(gè)提供者將會(huì)提升應(yīng)用的性能,因?yàn)樗粫?huì)在每次請求時(shí)都從文件系統(tǒng)加載。

想要延遲加載一個(gè)提供者,設(shè)置 defer屬性為 true并定義一個(gè) providers方法,該方法返回該提供者注冊的服務(wù)容器綁定:

<?php

namespace App\Providers;

use Riak\Connection;
use Illuminate\Support\ServiceProvider;

class RiakServiceProvider extends ServiceProvider{
    /**
     * 服務(wù)提供者加是否延遲加載.
     *
     * @var bool
     */
    protected $defer = true;

    /**
     * 注冊服務(wù)提供者
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('Riak\Contracts\Connection', function ($app) {
            return new Connection($app['config']['riak']);
        });
    }

    /**
     * 獲取由提供者提供的服務(wù).
     *
     * @return array
     */
    public function provides()
    {
        return ['Riak\Contracts\Connection'];
    }

}

Laravel 編譯并保存所有延遲服務(wù)提供者提供的服務(wù)及服務(wù)提供者的類名。然后,只有當(dāng)你嘗試解析其中某個(gè)服務(wù)時(shí) Laravel 才會(huì)加載其服務(wù)提供者。