PHP中的服務容器與依賴注入的思想


依賴注入

 

當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返回一個對象.

擁有一個明確的學習思路能更高效化的學習

 

點此加入該群學習


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM