1

导语

laravel 的服务提供者,是框架的核心,提供了路由、日志、缓存等功能。这里要实现的需求是使用第三方 API 获取天气情况,涉及到服务提供者、契约、依赖注入等方面。相关内容可以通过下方参考资料进行了解,本文内容不进行展开介绍,代码可查看 GitHub

创建服务提供者

  1. 可以使用 artisan 快捷的创建服务提供者,执行 php artisan make:provider WeatherServiceProvider 即在 app/Providers 目录下创建了 WeatherServiceProvider.php 文件;
  2. config/app.php 中注册服务提供者,在 providers 数组中将创建的服务提供者 App\Providers\WeatherServiceProvider::class, 写入,如下

注册服务提供者

创建契约

  1. app 目录下新建 Contracts 目录用以存放契约文件;
  2. app/Contracts 目录下创建契约,即 Weather.php 接口文件。在接口中只定义了 public function getWeather($cityName); 一个方法用于获取天气信息;

实现契约

  1. app 目录下新建 Service/Weather 目录用于存放实现 Weather.php 契约的文件;
  2. 选择一个第三方的天气 API 来实现契约。这里使用的是心知天气。关于 API 的调用,可以查看文档
  3. 最终创建的文件是 app/Service/Weather/Xinzhi.php。继承了 Weather.php 接口文件,所有要实现 getWeather 方法,代码可查看 GitHub
  4. 这里先埋个伏笔。除了上面的 Xinzhi.php,另外选择和风天气实现契约,文件为 app/Service/Weather/Hefeng.php。代码查看 GitHub

服务提供者绑定

我们已经实现了契约,接下来就是绑定具体实现类。回到开始创建的服务提供者,在 register 方法中添加如下代码

$this->app->bind('App\Contracts\Weather', function() {
    return new Xinzhi();
});

最后就可以正常使用了。新建路由,然后测试。试下通过依赖注入调用

public function getWeather(Request $request, Weather $weather)
{
    return $weather->getWeather($request->input('city', 'beijing'));
}

没有问题

测试

解耦

完成上述所有步骤,这个需求已经实现了。看起来很麻烦是吧,完全可以封装一个函数,直接调用就可以了,没有必要自定义服务提供者、创建契约。实际上述步骤,其中的一个目的就是小标题那两个字——解耦
假设一下,我们需要在很多代码中使用这个功能,突然有一天,这个 API 挂了,怎么办?四处去查找、检查代码,然后再去修改,同时要注意参数、返回值等。光是听起来就很烦了。这个时候,如果我们的代码按照上述的步骤进行开发,解决方法就大不相同了。简而言之,一行代码就可以搞定。
还记得上面那个伏笔吧,一共有两个实例实现了接口。将自定义的服务提供者 register 做如下修改

$this->app->bind('App\Contracts\Weather', function() {
       // return new Xinzhi();
        return new Hefeng();
});

修改了契约的绑定,所有使用 Weather 契约进行依赖注入的实例,都会由 Xinzhi.php 实例切换到 Hefeng.php 实例。

契约当然不止解耦这一个作用,代码更容易理解、更方便维护,甚至可以当做简明的开发文档。更多的深入理解,请查看下方参考资料。


参考资料:底层原理 —— 服务提供者底层原理 —— 契约(Contracts)Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI) Laravel 从学徒到工匠系列 依赖注入篇


Haoyuqi
472 声望23 粉丝

PHPer