第一步:定义契约接口类
<?php
namespace App\Contracts;
interface TestContract
{
public function say($info):string;
}
第二步:定义子类服务实现接口
<?php
namespace App\Services;
use App\Contracts\TestContract;
class TestService implements TestContract
{
public function say($info):string
{
dd($info);
}
}
第三步:创建服务提供者
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\TestService;
class TestServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('App\Contracts\TestContract', function(){
return new TestService();
});
}
public function boot()
{
}
}
第四步:注册服务提供者
// app\config\app.php
<?php
'providers' => [
# 此处省略其它内容
App\Providers\TestServiceProvider::class,
],
第五步:测试服务提供者
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Contracts\TestContract;
class TestController extends Controller
{
public function test(TestContract $test)
{
$test->say('test');
}
}
以上内容是按照laravel文档创建的,但是测试的时候,第三步和第四步可有可无,不注册服务提供者,在第五步的控制器中也能调用say()方法;那请问这个服务提供者到底有什么作用啊??
服务提供者更多的是用于对于 Laravel 框架的扩展,因为在日常的项目开发过程中,我们总会遇到一些,通用性的内容,比如跨域处理、文件上传、消息推送、发送短信等,这些可以独立于项目的组件。
如果按照传统的不分离的形式,你就需要在 app 创建一个目录来保存这些内容,并且,这些可能都会有各自的配置项,那你就还需要创建对应的配置文件,现在你只需要调用 App 命令空间下对应的类,就可以调用这些服务。
但是,如果你要新建一个项目,你现在就只有把当前的代码拷贝一份出去(别忘了配置项),到新项目,然后复用,这是最理想的状态。
但是你想一下,如果因为某个功能,你修改了这个类,然后其他项目又用不到,那拷贝的时候,可能还要清理掉这些内容,又或者,这个类里面有个 BUG ,你就要修改每一个项目。
而现代化开发,讲究的就是一个复用,提高代码的复用性,减少重复(CV)工作。
现在换个方式,你可以创建一个 composer 包,然后把所有代码都搬到这个包里面去,包括配置项。然后把这个 composer 包发布到仓库去(可以自建、也可以使用公共仓库),紧接着,你就可以使用
composer require
来安装你新提取出去的这个包了。安装完成后,你的新包可能并不能完好的工作,比如提到的契约接口注册、配置项获取等。因为这会儿他只是一个普通的包。
现在,做一件事情,创建一个 ServiceProvider ,就把所有的资产(契约接口注册、配置项注册、本地化、模板)等进行注册。
然后,你还需要在 laravel 中去注册这个 ServiceProvider ,然后你得扩展包里面的内容就可以正常工作了,以后新建项目的时候,只需要 composer require 一下这个包,然后注册一下 ServiceProvider 就可以了,如果某个类有 BUG ,你现在只需要修改这个包的代码,在其他项目更新一下,即可拿到最新的代码。
注:自 laravel 5.5 起,composer 包可以配置自动注册发现服务提供者,不再需要手动去注册,变得更爽了
说到这里,或许你能理解一些,但是这大部分的功劳仍然归功于 composer ,而服务提供者(ServiceProvider) 更像是一个清单文件,来告诉 Laravel ,应该怎么处理这些资源,或者启动哪些服务。
简单的项目中,一般并不太需要自行创建 ServiceProdiver ,因为你可以简单的在自带的 AppServiceProvier 中编写你的代码,创建单独的服务提供者可以为了以后扩展打下基础。
你上面说到的契约接口注册绑定,只是服务提供者的冰山一角,可以参考文档中关于 扩展包开发 章节的内容。
关于为什么需要接口绑定,可以继续查阅有关:依赖注入、依赖倒置 方面的知识。