依赖注入服务容器(实现控制反转)


依赖注入

构造函数参数类型注入

namespace app\web\controller;


use lib\markdown\Markdown;
use lib\test\Audi;

class Test extends Base
{
    private $markdown;

    public function __construct(Markdown $markdown)
    {
        parent::__construct();
        $this->markdown = $markdown;
    }

    public function index()
    {
        $this->markdown->buildHtml();
    }
}
说明:在控制器构造函数里面直接声明了Markdown这个类参数,框架会自动实例化Markdown这个类,并传给构造函数
注意,这里我们没有注册Markdown这个服务

举例说明

服务提供者

namespace common\provider;


use lib\markdown\Markdown;
use lib\test\Saler;
use lib\test\CarFactory;
use Timo\Core\Container;
use Timo\Support\ServiceProvider;

class CommonProvider extends ServiceProvider
{
    public function register()
    {
        $this->container->singleton([Markdown::class => 'markdown'], Markdown::class);

        $this->container->singleton([Saler::class => 'Saler'], function (Container $container) {
            /** @var CarFactory $carFactory */
            $carFactory = $container->get(CarFactory::class);
            return new Saler($carFactory, '刘慧', '成都');
        });
    }
}

控制器

namespace app\cli\controller;


use lib\markdown\Markdown;
use lib\test\Saler;

class Test extends Cli
{
    private $markdown;
    private $saler;

    public function __construct(Markdown $markdown, Saler $saler)
    {
        parent::__construct();
        $this->markdown = $markdown;
        $this->saler = $saler;
    }

    public function container()
    {
        $this->markdown->buildHtml();
        $this->saler->audi();
    }
}

一般注入方式

namespace app\web\controller;

use lib\test\Audi;

class Test extends Base
{
    public function index()
    {
        $car = $this->container->get('car');
        $car->run();
        
        $audi = $this->container->get(Audi::class);
        $audi->run();
    }
}
看见没,上面的car是我们给lib\test\Car取的别名,下面的Audi:class,也就是lib\test\Audi,我们同样也可以取别名
$this->container->singleton([Audi::class => 'audi'], function() {
    $car = $this->container->get('car');
    $car->design('Audi A6');
    return new Audi($car);
});

然后,就可以这么用了:

$audi = $this->container->get('audi');
也可以这样取别名
$this->container->alias(Audi::class, 'audi');
$this->container->alias('lib\test\Audi', 'audi');
上面两个等价的

注册方式

bind

singleton

instance

将接口绑定到实现

首先我们定义一个接口

namespace app\contract;


interface Sms
{
    public function send($mobile, $content, $template_id);
}

定义具体的sms类

namespace lib\alisms;


use app\contract\Sms;

class Client implements Sms
{
    protected $type = 1;

    public function send($mobile, $content, $template_id)
    {
        echo 'aliYun send sms: Mobile->' . $mobile . ' Content->' . $content . '<br>';
    }
}

在控制器中使用

在使用之前需要先绑定

$this->container->singleton([Sms::class => 'sms'], 'lib\alisms\Client');
namespace app\web\controller;


use app\contract\Sms;
use Timo\Core\Controller;

class Test extends Controller
{
    private $sms;

    public function __construct(Sms $sms)
    {
        parent::__construct();
        
        $this->sms = $sms;
    }
 
    public function run()
    {
        $this->sms->send('13800000008', 'Hello TimoPHP', 1009);
    }
}