laravel 自定义服务提供者
导语
laravel 的服务提供者,是框架的核心,提供了路由、日志、缓存等功能。这里要实现的需求是使用第三方 API 获取天气情况,涉及到服务提供者、契约、依赖注入等方面。相关内容可以通过下方参考资料进行了解,本文内容不进行展开介绍,代码可查看 GitHub。
创建服务提供者
- 可以使用
artisan
快捷的创建服务提供者,执行php artisan make:provider WeatherServiceProvider
即在app/Providers
目录下创建了WeatherServiceProvider.php
文件; - 在
config/app.php
中注册服务提供者,在providers
数组中将创建的服务提供者App\Providers\WeatherServiceProvider::class,
写入,如下
创建契约
- 在
app
目录下新建Contracts
目录用以存放契约文件; - 在
app/Contracts
目录下创建契约,即Weather.php
接口文件。在接口中只定义了public function getWeather($cityName);
一个方法用于获取天气信息;
实现契约
- 在
app
目录下新建Service/Weather
目录用于存放实现Weather.php
契约的文件; - 选择一个第三方的天气 API 来实现契约。这里使用的是心知天气。关于 API 的调用,可以查看文档;
- 最终创建的文件是
app/Service/Weather/Xinzhi.php
。继承了Weather.php
接口文件,所有要实现getWeather
方法,代码可查看 GitHub; - 这里先埋个伏笔。除了上面的
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 从学徒到工匠系列 依赖注入篇。