Laravel服務提供者

概念和意義

把組件統一管理起來形成一個服務,和業務層分離,業務代碼層調用各種服務。
當修改獨立服務的底層實現時,不會影響業務層,達到了降低代碼耦合,增強代碼分層的架構設計。

使用示例

  1. 執行php artisan make:provider RepositoriesServiceProvider創建一個服務提供者。
  2. 在config/app.php的providers數組中增加該服務提供者。
    	...
    	// laravel框架收到請求後,會在引導服務啓動時,加載這裏的配置文件,並調用服務提供者的方法
    	App\Providers\RepositoriesServiceProvider::class,
    	...
    
  3. 在app目錄下創建Repositories文件夾,用於存儲服務。
  4. 在上一步創建的Repositories文件夾內,創建一個Interfaces文件夾,用於存儲接口類。
  5. 在Interfaces文件夾中創建一個SMS接口類,用於約束SMS類的實現和業務層使用時的抽象。
    <?php
    namespace App\Repositories\Interfaces;
    
    interface SMSInterface {
        public function send(string $string);
    }
    
  6. 在Repositories文件夾中創建一個對SMS接口的實現類。
    <?php
    
    namespace App\Repositories;
    
    use App\Repositories\Interfaces\SMSInterface;
    
    class AliyunSMS implements SMSInterface
    {
        public function send(string $string)
        {
            echo $string;
        }
    }
    
    
  7. 在第一步命令行創建的服務提供者中,把我們上面實現的SMS服務註冊到該服務提供者中,作爲該服務提供者的一部分 。
    	...
        public function register()
        {
        	// 當該服務底層不用AliyunSMS作爲實現時,只需要在這裏綁定對應新的實現即可,無需改動業務層。
            $this->app->bind('App\Repositories\Interfaces\SMSInterface', 'App\Repositories\AliyunSMS');
        }
        ...
    
  8. 在控制器中使用
    	use App\Repositories\Interfaces\SMSInterface;
    	...
        public function test(Request $request, SMSInterface $sms)
        {
            $sms->send('test123');
        }
        ...
    

底層是如何加載的?

public/index.php中調用從容器中make出來的kernel類的handle方法中,其中會調用一個bootstrap方法,也就是引導方法。
其中會把Kernel類中的bootstrappers數組變量內預定義的需要啓動的服務,全部啓動。

Illuminate\Foundation\Http\Kernel:

    protected $bootstrappers = [
        'Illuminate\Foundation\Bootstrap\DetectEnvironment',
        'Illuminate\Foundation\Bootstrap\LoadConfiguration',
        'Illuminate\Foundation\Bootstrap\ConfigureLogging',
        'Illuminate\Foundation\Bootstrap\HandleExceptions',
        'Illuminate\Foundation\Bootstrap\RegisterFacades',
        'Illuminate\Foundation\Bootstrap\RegisterProviders',
        'Illuminate\Foundation\Bootstrap\BootProviders',
    ];

可以看到有很多服務,其中有一個RegisterProviders服務。
該服務內的bootstrap方法中調用了容器類的registerConfiguredProviders方法

Illuminate\Foundation\Application:

    /**
     * Register all of the configured providers.
     *
     * @return void
     */
    public function registerConfiguredProviders()
    {
        $manifestPath = $this->getCachedServicesPath();

        (new ProviderRepository($this, new Filesystem, $manifestPath))
                    ->load($this->config['app.providers']);
    }

可見該方法讀取了config/app.php配置文件中的providers數組,然後使用了\Illuminate\Foundation\ProviderRepository類的load方法。
load方法中有一句代碼片段:$this->app->register($this->createProvider($provider));

也就是又迭代該的providers數組,使用容器的register方法進行處理,容器的register方法中有一個判斷爲:

        if (method_exists($provider, 'register')) {
            $provider->register();
        }

如果該服務內存在register方法,則調用該服務的register方法。
也就是調用了我們創建的服務提供者文件的register方法,將服務所需的類綁定註冊到了容器中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章