概念和意義
把組件統一管理起來形成一個服務,和業務層分離,業務代碼層調用各種服務。
當修改獨立服務的底層實現時,不會影響業務層,達到了降低代碼耦合,增強代碼分層的架構設計。
使用示例
- 執行
php artisan make:provider RepositoriesServiceProvider
創建一個服務提供者。 - 在config/app.php的providers數組中增加該服務提供者。
... // laravel框架收到請求後,會在引導服務啓動時,加載這裏的配置文件,並調用服務提供者的方法 App\Providers\RepositoriesServiceProvider::class, ...
- 在app目錄下創建Repositories文件夾,用於存儲服務。
- 在上一步創建的Repositories文件夾內,創建一個Interfaces文件夾,用於存儲接口類。
- 在Interfaces文件夾中創建一個SMS接口類,用於約束SMS類的實現和業務層使用時的抽象。
<?php namespace App\Repositories\Interfaces; interface SMSInterface { public function send(string $string); }
- 在Repositories文件夾中創建一個對SMS接口的實現類。
<?php namespace App\Repositories; use App\Repositories\Interfaces\SMSInterface; class AliyunSMS implements SMSInterface { public function send(string $string) { echo $string; } }
- 在第一步命令行創建的服務提供者中,把我們上面實現的SMS服務註冊到該服務提供者中,作爲該服務提供者的一部分 。
... public function register() { // 當該服務底層不用AliyunSMS作爲實現時,只需要在這裏綁定對應新的實現即可,無需改動業務層。 $this->app->bind('App\Repositories\Interfaces\SMSInterface', 'App\Repositories\AliyunSMS'); } ...
- 在控制器中使用
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方法,將服務所需的類綁定註冊到了容器中。