果冻想
认真玩技术的地方

Laravel初级教程之服务提供者

简介

服务提供者,见名知意,就是提供服务的地方。我们再回顾一下上一篇《Laravel初级教程之服务容器》,在这篇文章中说到,服务容器是“盛放”服务的地方,那我们通过什么地方把我们开发好的服务放到服务容器呢?而服务提供者就是我们将服务放到服务容器的地方。更官方的一点说法就是:

服务提供者是Laravel应用启动的中心,你自己的应用以及所有Laravel的核心服务都是通过服务提供者启动。当然启动这些服务,需要加载注册服务,包括注册服务容器绑定、事件监听器、中间件甚至路由。服务提供者是应用配置的中心。

各位读者看看,服务提供者是应用配置的中心。这样你就应该知道服务提供者的作用和地位了吧。对于这样重要的一部分,接下来,我会循序渐进,通过代码示例,给大家总结如何完成一个完整的服务提供者的开发,最后会通过一个完整的短信发送的实例,来完成服务容器和服务提供者的实战演练。

为了方便配合下面内容的展开,我这里需要先定义一个接口,以及对应的实现。

接口定义:

<?php
namespace App\Service\interfaces;

interface ISMS
{
    function sendSMS($phoneNum, $smsContent);
}

对应接口实现类:

<?php
namespace App\Service\impl;

use App\Service\interfaces\ISMS;
use Yunpian\Sdk\YunpianClient;

class YunPianSMS implements ISMS
{
    function sendSMS($phoneNum, $smsContent) {
        //初始化client,apikey作为所有请求的默认值
        $clnt = YunpianClient::create(env("YUNPIAN_API_KEY"));
        $param = [YunpianClient::MOBILE => $phoneNum,YunpianClient::TEXT => $smsContent];
        $r = $clnt->sms()->single_send($param);
        if($r->isSucc()) {
            $r->data();
        }
    }
}

开发服务提供者

所有的服务提供者都继承自Illuminate\Support\ServiceProvider类。这个抽象类要求提供者必须最少定义一个register方法。在register方法中应该只绑定内容到服务容器。永远不要尝试在其中注册任何的事件监听,路由或者其它功能。因为我们可能使用了还未注册的服务,从而导致异常。

我们可以通过make:provider命令来非常便捷的生成一个新的服务提供者:

php artisan make:provider SMSServiceProvider

执行成功后,便在app/Providers目录下生成一个SMSServiceProvider.php文件,生成的模板内容如下:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class SMSServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

可以看到,生成的服务提供者模板中就只有两个方法:bootregister。而我们在开发服务提供者时,也都是在这两个方法中“搞事情”;也就是说,搞明白在boot方法中该写点什么,又或在register方法中写点什么,这样就就掌握了如何开发服务提供者。下面对这两个方法分别进行详细的总结。

  • boot方法
    对于boot方法,需要记住以下一点:

    boot方法在所有服务提供者被注册以后才会被调用,这就是说我们可以在其中访问框架已注册的所有其它服务。

    boot方法在register方法之后调用,这就意味着,我们无须担心在注入某个实例的时候,它还没有被绑定或实例化。

    在实际工作中,boot中一般完成启动相应的服务的工作。

  • register方法
    对于register方法,需要记住以下一点:

    register方法中只绑定服务到服务容器,而不要做其它事情。

根据上面对bootregister两个方法的认识,接下来我们来完成这个SMSServiceProvider

public function register()
{
    $this->app->singleton("SMSService", function($app) {
        return new YunPianSMS();
    });
}

注册服务提供者

服务提供者多了,系统难免难于管理,为了更有条理的管理好各类服务提供者,所有的服务提供者都被注册在config/app.php配置文件中。这个文件包含了providers数组,这数组列出了所有服务提供者的名字。默认的,laravel中的核心服务都被注册在这个数组里。这些提供者启动了laravel中的核心组件,如邮件,队列,缓存和其他。

现在我们可以在该数组中进行添加注册服务提供者:

'providers' => [
  // Other Service Providers

  App\Providers\SMSServiceProvider::class
],

延迟加载

如果我们的服务提供者中提供的服务,并不会被每次请求都用到,或者很少用到。那么我们可以选择推迟注册。这样这些服务只有在真正被需要用到时才会进行注册。推迟注册能够提高应用的性能,因为它不会在所有请求到来时都通过文件系统来加载。

为了推迟服务提供者的加载,我们可以在提供者类中设置defer属性为true,并且定义一个provides方法。provides方法会返回服务提供者注册的服务容器的绑定,最终,我们的服务提供者应该似乎这个样子:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Service\impl\YunPianSMS;

class SMSServiceProvider extends ServiceProvider
{
    /**
     * 服务提供者加是否延迟加载.
     *
     * @var bool
     */
    protected $defer = true;

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton("SMSService", function($app) {
            return new YunPianSMS();
        });
    }

    /**
     * 获取由提供者提供的服务.
     *
     * @return array
     */
    public function provides()
    {
        return ['SMSService'];
    }
}

实战演练

写到这里,如果你亲自把文中的代码都敲了一遍,你会发现这就是一个短信下发的Demo,去云片网申请一个测试账号,即可完成这篇文章的短信下发功能了。

Route::get('/sendSMS', function() {
    $smsService = resolve('SMSService');

    $phoneNum = '1503497XXX';
    $smsContent = '【果冻想】认真玩技术的地方。';
    $smsService->sendSMS($phoneNum, $smsContent);
});

总结

断断续续,花费了将近3天的时间,把这篇文章总结完成。由于服务提供者的作用太重要了,导致自己在总结时也是不敢有一丝懈怠,阅读了多篇文章后,才敢动手开始总结。每总结一篇文章,都是对自己的一次提高;也是自己对知识点理解的一次升华。透彻的理解每个知识点,在后续的填坑生涯中,将会得心应手。

果冻想,认真玩技术的地方。

2018年3月31日 于内蒙古呼和浩特。

赞(37) 打赏
未经允许不得转载:果冻想 » Laravel初级教程之服务提供者
关注微信公众号
关注微信公众号和果冻一起分享你的疑惑与心得。
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

玩技术,我们是认真的

联系我们关于果冻

请我喝杯咖啡也是不错的

支付宝扫一扫打赏

微信扫一扫打赏