前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP系列 | 依赖注入容器和服务定位器

PHP系列 | 依赖注入容器和服务定位器

作者头像
Tinywan
发布2019-08-20 11:07:32
9890
发布2019-08-20 11:07:32
举报
文章被收录于专栏:开源技术小栈开源技术小栈

依赖注入之-容器

依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象。注册会用到一个依赖关系名称和一个依赖关系的定义。依赖关系名称可以是一个类名,一个接口名或一个别名。依赖关系的定义可以是一个类名,一个配置数组,或者一个 PHP 回调。

一、常见注入方式

1、构造方法注入(Constructor Injection)

在参数类型提示的帮助下,DI 容器实现了构造方法注入。当容器被用于创建一个新对象时, 类型提示会告诉它要依赖什么类或接口。容器会尝试获取它所依赖的类或接口的实例, 然后通过构造器将其注入新的对象。例如:

    class Foo

    {

        public function __construct(Bar $bar)

        {

        }

    }

    $foo = $container->get('Foo');

    // 上面的代码等价于:

    $bar = new Bar;

    $foo = new Foo($bar);
2、方法注入(Method Injection)

通常,类的依赖关系传递给构造函数,并且在整个生命周期中都可以在类内部使用。通过方法注入,可以提供仅由类的单个方法需要的依赖关系, 并将其传递给构造函数可能不可行,或者可能会在大多数用例中导致太多开销。

    class MyClass extends \yii\base\Component

    {

        public function __construct(/*Some lightweight dependencies here*/, $config = [])

        {

            // ...

        }

        public function doSomething($param1, \my\heavy\Dependency $something)

        {

            // do something with $something

        }

    }
3、Setter 和属性注入(Setter and Property Injection)

Setter 和属性注入是通过配置提供支持的。当注册一个依赖或创建一个新对象时,你可以提供一个配置, 该配置会提供给容器用于通过相应的 Setter 或属性注入依赖。例如:

    use yii\base\BaseObject;

    class Foo extends BaseObject

    {

        public $bar;

        private $_qux;

        public function getQux()

        {

            return $this->_qux;

        }

        public function setQux(Qux $qux)

        {

            $this->_qux = $qux;

        }

    }

    $container->get('Foo', [], [

        'bar' => $container->get('Bar'),

        'qux' => $container->get('Qux'),

    ]);

二、直接注入类到容器中

TP5.1 绑定一个类到容器中(第一个参数直接传入类名)

1、使用容器

    // 绑定类库标识

    Container::getInstance()->bindTo(GameService::class);

    // 自动实例化

    $obj = Container::get(GameService::class);

    // 快速调用

    halt($obj->test());

2、使用助手函数

    // 绑定类库标识

    bind(GameService::class);

    // 快速调用(自动实例化)

    $obj = app(GameService::class);

    halt($obj);

Yii2.0 注册一个同类名一样的依赖关系

    $container = new \yii\di\Container;

    // 注册一个同类名一样的依赖关系,这个可以省略。

    $container->set(GameService::class);

三、绑定类标识

TP5.1 可以对已有的类库绑定一个标识(唯一),便于快速调用

1、使用容器

    // 绑定类库标识

    Container::getInstance()->bindTo('game_service2',GameService::class);

    // 快速调用(自动实例化)

    $obj = Container::get('game_service2');

    halt($obj);

2、使用助手函数

    // 绑定类库标识

    bind('game_service',GameService::class);

    // 快速调用(自动实例化)

    $obj = app('game_service');

    // 带参数实例化调用

    $obj = app('game_service',['file']);

    halt($obj->test());

Yii2.0 注册一个别名

    $container = new \yii\di\Container;

    $container->set('foo', 'yii\db\Connection');

    // 创建一个 Connection 实例

    $obj = $container->get('foo');

四、绑定闭包

TP5.1 使用

    // 使用助手函数

    bind('sayHello', function ($name) {

        return 'hello,' . $name;

    });

    echo app('sayHello',['thinkphp']);

    // 使用容器

    Container::getInstance()->bindTo('sayTinywan',function ($age){

        return 'Tinywan is '.$age;

    });

    echo Container::get('sayTinywan',[24]);

Yii2.0 注册一个PHP回调

    // 每次调用 $container->get('db') 时,回调函数都会被执行。

    $container->set('db', function ($container, $params, $config) {

        return new \yii\db\Connection($config);

    });

四、类绑定到接口

// 绑定think\LoggerInterface接口实现到think\Log
bind('think\LoggerInterface','think\Log');

使用接口作为依赖注入的类型

    <?php

    namespace app\index\controller;

    use think\LoggerInterface;

    class Index

    {

        public function hello(LoggerInterface $log)

        {

            $log->record('hello,world!');

        }    

    }

或者使用容器

    // 绑定 app\driver\DriverInterface接口实现到 app\driver\YoungDriver

    $driver = Container::getInstance()->bindTo(DriverInterface::class,YoungDriver::class);

    $car = Container::get(Car::class, [$driver]);

    var_dump($car->run());

依赖注入之-服务定位器

服务定位器是一个了解如何提供各种应用所需的服务(或组件)的对象。在服务定位器中, 每个组件都只有一个单独的实例,并通过ID 唯一地标识。用这个 ID 就能从服务定位器中得到这个组件。

TP5.1 使用

1、配置文件 provider.php

系统会自动批量绑定类库到容器中

    // 应用容器绑定定义

    return [

        'game_player' => \app\common\repositories\player\Game::class,

        'random' => \app\common\repositories\game\RandomGroup::class

    ];

2、那类玩家在玩那个游戏

    // 声明那类玩家

    Container::getInstance()->bindTo(PlayerInterface::class,TeacherPlayer::class);

    // 要玩那个游戏

    $game = app('random');

    // 获取玩家实例

    $player = app('game_player');

    // 玩家开始玩什么游戏

    halt($player->play($game));

3、携带参数

    // 声明那类玩家

    Container::getInstance()->bindTo(PlayerInterface::class, StudentPlayer::class);

    // 要玩那个游戏

    $game = app('random');

    // 获取玩家实例

    $parms = ['caode' => 200, 'name' => 'wangwang'];

    $player = app('game_player',['ddd']);

    // 玩家开始玩什么游戏

    halt($player->play($game,$parms));
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Tinywan的杂货摊 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 依赖注入之-容器
    • 一、常见注入方式
      • 1、构造方法注入(Constructor Injection)
      • 2、方法注入(Method Injection)
      • 3、Setter 和属性注入(Setter and Property Injection)
    • 二、直接注入类到容器中
      • 三、绑定类标识
        • 四、绑定闭包
          • 四、类绑定到接口
          • 依赖注入之-服务定位器
            • TP5.1 使用
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档