概念和意义
把组件统一管理起来形成一个服务,和业务层分离,业务代码层调用各种服务。
当修改独立服务的底层实现时,不会影响业务层,达到了降低代码耦合,增强代码分层的架构设计。
使用示例
- 执行
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方法,将服务所需的类绑定注册到了容器中。