服务提供者


定义

服务提供者就是,当前应用需要哪些服务/组件,我们就在服务提供者里面定义哪些服务/组件,方便在程序里面直接使用,解决了类与类之间的耦合

存放位置

可以在任意位置建立服务提供者,我们推荐在 /common/provider 目录下新建服务提供者类,服务提供者类必须继承Timo\Support\ServiceProvider,
我们只需在类的register方法里面注册服务即可,看下面的例子
服务提供者可以是多个,我们可以使用服务提供者下面的$container(服务容器实例)属性来注册服务

新建服务提供者

创建一个空的服务提供者CommonProvider,意思就是没有注册任何一个服务,路径:/common/provider/CommonProvider
<?php
namespace common\provider;

class CommonProvider extends ServiceProvider
{
    public function register()
    {
        
    }
}

注册服务

注册服务只需在register方法里面注册服务即可,注册方式有很多种

方式一,普通注册,通过get获取服务时,获取到的都是全新服务实例

$this->container->bind();

方式二,单例模式注册,通过get获取服务时,获取到的都是同一个服务器实例

$this->container->singleton();

方式三,注册一个服务器实例

$this->container->instance();

举例说明

<?php
namespace common\provider;

use lib\markdown\Markdown;
use Timo\Support\ServiceProvider;

class CommonProvider extends ServiceProvider
{
    public function register()
    {
        $this->container->bind([Car::class => 'car'], function() {
            return new Car();
        });
        
        $this->container->singleton('markdown', Markdown::class);
        $this->container->singleton('markdown', 'lib\markdown\Markdown');
        
        $this->bind(['lib\pay\Client' => 'pay'], function($container) {
            $car = $container->get('car');
            return new Client($car);
        });
    }
}
上面我们注册了一个名为car的服务,并且是以单例的模式注册的,可以在register方法里面注册多个服务

服务别名

namespace common\provider;

use lib\markdown\Markdown;
use Timo\Support\ServiceProvider;

class CommonProvider extends ServiceProvider
{
    public function register()
    {
        //说明 Markdown::class 等于 'lib\markdown\Markdown' , 服务别名就是markdown
        $this->container->singleton([Markdown::class => 'markdown'], Markdown::class);
    }
}

注册服务提供者

我们要告诉框架有哪些服务提供者

可以在配置文件中providers项定义服务提供者,可注册多个
'providers' => [
    app\provider\CommonProvider::class,
    app\provider\PayProvider::class,
    app\provider\Ossprovider::class
]

怎样获取服务容器实例

我们要在其它类里面使用服务容器,该怎么获取呢?
$container = App::container();
比如,我们要在控制器里面使用,我们可以放到所有控制器的基类里面,比如Base、Common控制器
namespace app\web\controller;


use Timo\Core\Controller;

class Base extends Controller
{
    protected $container;

    public function __construct()
    {
        parent::__construct();

        $this->container = App::container();
    }
}    
然后,我们就可以在其它控制器里面方便的使用了
namespace app\web\controller;


use app\web\model\DocumentModel;
use lib\markdown\Markdown;
use Timo\Core\Exception;
use Timo\Core\Request;

class Document extends Common
{
    /**
     * 文档详情页
     *
     * @param int $id
     * @return string
     * @throws Exception
     */
    public function show($id = 0)
    {
        $id = (int) $id;
        if ($id <= 0) {
            throw new Exception('文档ID不能小于零');
        }

        //获取文档标题
        $document = (new DocumentModel())->getDocument($id);
        if (!$document) {
            throw new Exception('文档'.$id.'不存在');
        }

        //获取文档内容
        /**
         * @var $markdown Markdown
         */
        $markdown = $this->container->get('markdown');
        $doc_html = $markdown->makeHtmlFragment('document', $id, false);

        $this->assign('title', $document['title']);
        $this->assign('doc', $doc_html);

        return $this->render();
    }
}