依赖注入

当A类需要依赖于B类,也就是说需要在A类中实例化B类的对象来使用时候,如果B类中的功能发生改变,也会导致A类中使用B类的地方也要跟着修改,导致A类与B类高耦合。这个时候解决方式是,A类应该去依赖B类的接口,把具体的类的实例化交给外部。

就拿我们业务中常用的通知模块来说。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

<?php

/**

 * 定义了一个消息类

 * Class Message

 */

class  Message{

  public function seed()

  {

      return 'seed email';

  }

}

/*

 * 订单产生的时候 需要发送消息

 */

class Order{

    protected $messager = '';

    function __construct()

    {

        $this->messager = new Message();

    }

    public function seed_msg()

    {

        return $this->messager->seed();

    }

}

$Order = new Order();

$Order->seed_msg();

上面的代码是我们传统的写法。首先由个消息发送的类。然后在我们需要发送消息的地方,调用发送消息的接口。有一天你需要添加一个发送短信的接口以满足不同的需求。那么你会发现你要再Message类里面做修改。同样也要再Order类里面做修改。这样就显得很麻烦。这个时候就有了依赖注入的思路。下面把代码做一个调整

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

<?php

/**

 * 为了约束我们先定义一个消息接口

 * Interface Message

 */

interface  Message{

  public function seed();

}

/**

 * 有一个发送邮件的类

 * Class SeedEmail

 */

class SeedEmail implements Message

{

    public function seed()

    {

        return  'seed email';

        // TODO: Implement seed() method.

    }

}

/**

 *新增一个发送短信的类

 * Class SeedSMS

 */

class SeedSMS implements Message

{

    public function seed()

    {

        return 'seed sms';

        // TODO: Implement seed() method.

    }

}

/*

 * 订单产生的时候 需要发送消息

 */

class Order{

    protected $messager = '';

    function __construct(Message $message)

    {

        $this->messager = $message;

    }

    public function seed_msg()

    {

        return $this->messager->seed();

    }

}

//我们需要发送邮件的时候

$message = new SeedEmail();

//将邮件发送对象作为参数传递给Order

$Order = new Order($message);

$Order->seed_msg();

//我们需要发送短信的时候

$message = new SeedSMS();

$Order = new Order($message);

$Order->seed_msg();

这样我们就实现了依赖注入的思路,是不是很方便扩展了。

服务容器

我理解的服务容器就是一个自动产生类的工厂。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

<?php

/**

 * 为了约束我们先定义一个消息接口

 * Interface Message

 */

interface  Message{

    public function seed();

}

/**

 * 有一个发送邮件的类

 * Class SeedEmail

 */

class SeedEmail implements Message

{

    public function seed()

    {

        return  'seed email';

        // TODO: Implement seed() method.

    }

}

/**

 *新增一个发送短信的类

 * Class SeedSMS

 */

class SeedSMS implements Message

{

    public function seed()

    {

        return 'seed sms';

        // TODO: Implement seed() method.

    }

}

/**

 * 这是一个简单的服务容器

 * Class Container

 */

class Container

{

    protected $binds;

    protected $instances;

    public function bind($abstract, $concrete)

    {

        if ($concrete instanceof Closure) {

            $this->binds[$abstract] = $concrete;

        } else {

            $this->instances[$abstract] = $concrete;

        }

    }

    public function make($abstract, $parameters = [])

    {

        if (isset($this->instances[$abstract])) {

            return $this->instances[$abstract];

        }

        array_unshift($parameters, $this);

        return call_user_func_array($this->binds[$abstract], $parameters);

    }

}

//创建一个消息工厂

$message = new  Container();

//将发送短信注册绑定到工厂里面

$message->bind('SMS',function (){

     return   new  SeedSMS();

});

//将发送邮件注册绑定到工厂

$message->bind('EMAIL',function (){

   return new  SeedEmail();

});

//需要发送短信的时候

$SMS  = $message->make('SMS');

$SMS->seed();

container是一个简单的服务容器里面有bind,make两个方法

bind是向容器中绑定服务对象。make则是从容器中取出对象。

bind

在bind方法中需要传入一个 concrete 我们可以传入一个实例对象或者是一个闭包函数。

可以看到我这全使用的是闭包函数,其实也可以这样写

1

2

$sms = new  SeedSMS();

$message->bind('SMS',$sms);

后面这种写法与闭包相比的区别就是我们需要先实例化对象才能往容易中绑定服务。而闭包则是我们使用这个服务的时候才去实例化对象。可以看出闭包是有很多的优势的。

make

make方法就从容器中出去方法。里面首先判断了instances变量中是否有当前以及存在的服务对象,如果有直接返回。如果没有那么会通过 call_user_func_array返回一个对象.

  明确的学习思路能更高效化的学习

点此加入该群学习

PHP中的服务容器与依赖注入的思想的更多相关文章

  1. AspectCore中的IoC容器和依赖注入

    IOC模式和依赖注入是近年来非常流行的一种模式,相信大家都不陌生了,在Asp.Net Core中提供了依赖注入作为内置的基础设施,如果仍不熟悉依赖注入的读者,可以看看由我们翻译的Asp.Net Cor ...

  2. 轻松了解Spring中的控制反转和依赖注入(二)

    紧接上一篇文章<轻松了解Spring中的控制反转和依赖注入>讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作. 类 ...

  3. IOC容器的依赖注入

    1.依赖注入发生的时间 当Spring IoC容器完成了Bean定义资源的定位.载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入 ...

  4. springboot成神之——ioc容器(依赖注入)

    springboot成神之--ioc容器(依赖注入) spring的ioc功能 文件目录结构 lang Chinese English GreetingService MyRepository MyC ...

  5. Spring中的控制反转和依赖注入

    Spring中的控制反转和依赖注入 原文链接:https://www.cnblogs.com/xxzhuang/p/5948902.html 我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达 ...

  6. ASP.NET中IOC容器Autofac(依赖注入DI 控制反转IOC)

    IOC的一个重点是在程序运行中,动态的向某个对象提供它所需要的其他对象.这一点是通过DI来实现的.Autofac则是比较流行的一款IOC容器. IoC和DI有什么关系呢?其实它们是同一个概念的不同角度 ...

  7. 通过中看不中用的代码分析Ioc容器,依赖注入....

    /** * 通过生产拥有超能力的超人实例 来理解IOC容器 */ //超能力模组接口 interface SuperModuleInterface{ public function activate( ...

  8. ABP+AdminLTE+Bootstrap Table权限管理系统第四节--仓储,服务,服务接口及依赖注入

    在ABP框架中,仓储,服务,这块算是最为重要一块之一了.ABP框架提供了创建和组装模块的基础,一个模块能够依赖于另一个模块,一个程序集可看成一个模块, 一个模块可以通过一个类来定义这个模块,而给定义这 ...

  9. 简单理解laravel框架中的服务容器,服务提供者以及怎样调用服务

      laravel被称为最优雅的框架,最近正在学习中,对于用惯了thinkphp.ci框架的人来说,服务容器.服务提供者,依赖注入这些概念简直是一脸懵逼.我花了些时间梳理了一下,也不敢确定自己说的是对 ...

随机推荐

  1. POJO和JavaBean

    1.POJO POJO(Plain Ordinary Java Object):POJO就是一个简单的普通的Java对象,它不包含业务逻辑或持久逻辑等,但不是JavaBean.EntityBean等, ...

  2. 函数进阶(三) day14

    目录 昨日内容 迭代器 可迭代对象 迭代器对象 for循环原理 三元表达式 列表推导式 字典生成式 zip 生成器表达式 生成器 yield 递归 今日内容 匿名函数 内置方法 掌握 了解 异常处理 ...

  3. JVM(4) 类文件结构

    一.实现“平台无关性” 字节码(ByteCode)存储格式和虚拟机是实现语言无关性的基础.Java虚拟机不和包括Java在内的任何语言绑定,它只与“Clas”文件这种特定的二进制文件格式所关联,Cla ...

  4. python编译器的安装和pycharm的安装

    python编译器的安装 进入官网https://www.python.org/,根据提示安装 安装python编译器 pychram安装 下载地址: https://www.jetbrains.co ...

  5. python之深拷贝和浅拷贝

    1.当拷贝的是不可变数据类型(数值.字符串.元组),不管是深拷贝和浅拷贝,都指向的是同一地址: 2.当拷贝的对象是可变数据类型(列表.字典): (1)当浅拷贝的对象中无复杂子对象,原来值的改变不会影响 ...

  6. vue表单属性

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. kubernetes实战(二十七):CentOS 8 二进制 高可用 安装 k8s 1.16.x

    1. 基本说明 本文章将演示CentOS 8二进制方式安装高可用k8s 1.16.x,相对于其他版本,二进制安装方式并无太大区别.CentOS 8相对于CentOS 7操作更加方便,比如一些服务的关闭 ...

  8. pyarango整理

    目录: 连接数据库 创建数据库/集合/文档 检索筛选 更新 删除 调用AQL的方法 安装需要用到的python包: pip install pyarango 一.连接数据库: >>> ...

  9. 第三十五章 POSIX共享内存

    POSIX共享内存函数介绍 shm_open 功能: 用来创建或打开一个共享内存对象 原型: int shm_open(const char *name, int oflag, mode_t mode ...

  10. Python3爬虫(2)_利用urllib.urlopen发送数据获得反馈信息

    一.urlopen的url参数 Agent url不仅可以是一个字符串,例如:https://baike.baidu.com/.url也可以是一个Request对象,这就需要我们先定义一个Reques ...