PHP中的相關服務容器與依賴注入的相關解析

2020-07-16 10:05:38

依賴注入

當A類需要依賴於B類,也就是說需要在A類中範例化B類的物件來使用時候,如果B類中的功能發生改變,也會導致A類中使用B類的地方也要跟著修改,導致A類與B類高耦合。這個時候解決方式是,A類應該去依賴B類的介面,把具體的類的範例化交給外部。

就拿我們業務中常用的通知模組來說。

常規

<?php

/**
 * 定義了一個訊息類
 * Class Message 
 */

class  Message{

  public function seed()
  {
      return '灰太狼準備吃羊';
  }

}

/*
 * 訂單產生的時候 需要傳送訊息
 */
class Order{

    protected $messager = '';

    function __construct()
    {
        $this->messager = new Message();
    }

    public function seed_msg()
    {
        return $this->messager->seed();
    }
}

$Order = new Order();
echo $Order->seed_msg();

上面的程式碼是我們傳統的寫法。首先由個訊息傳送的類。然後在我們需要傳送訊息的地方,呼叫傳送訊息的介面。有一天你需要新增一個傳送簡訊的介面以滿足不同的需求。那麼你會發現你要再Message類裡面做修改。同樣也要再Order類裡面做修改。這樣就顯得很麻煩。這個時候就有了依賴注入的思路。

賴注入的思路

<?php

/**
 * 為了約束我們先定義一個訊息介面
 * Interface Message
 */

interface  Message{
  public function seed();
}

/**
 * 有一個傳送郵件的類
 * Class SeedEmail
 */
class SeedEmail implements Message
{
    public function seed()
    {
        return  '灰太狼發郵件給紅太狼說要吃烤全羊';
    }
}

/** 
 *新增一個傳送簡訊的類
 * Class SeedSMS
 */
class SeedSMS implements Message
{
    public function seed()
    {
        return  '灰太狼傳簡訊給紅太狼說要吃烤全羊';
    }
}

/*
 * 訂單產生的時候 需要傳送訊息
 */

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);
echo $Order->seed_msg();

echo "n";

//我們需要傳送簡訊的時候
$message = new SeedSMS();
$Order = new Order($message);
echo $Order->seed_msg();

我理解的服務容器就是一個自動產生類的工廠。

服務容器

<?php

/**
 * 為了約束我們先定義一個訊息介面
 * Interface Message
 */
interface  Message{
    public function seed();
}

/**
 * 有一個傳送郵件的類
 * Class SeedEmail
 */
class SeedEmail implements Message
{
    public function seed()
    {
        return  '灰太狼發郵件給紅太狼說要吃烤全羊';
    }
}

/** 
 *新增一個傳送簡訊的類
 * Class SeedSMS
 */
class SeedSMS implements Message
{
    public function seed()
    {
        return  '灰太狼傳簡訊給紅太狼說要吃烤全羊';
    }
}

/**
 * 這是一個簡單的服務容器
 * 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');
echo $SMS->seed();

echo "n";

$EMAIL  = $message->make('EMAIL');
echo $EMAIL->seed();

container是一個簡單的服務容器裡面有bind,make兩個方法

bind是向容器中系結服務物件。

make則是從容器中取出物件。

bind

在bind方法中需要傳入一個 concrete 我們可以傳入一個範例物件或者是一個閉包函數。
可以看到我這全使用的是閉包函數,其實也可以這樣寫

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

後面這種寫法與閉包相比的區別就是我們需要先範例化物件才能往容易中系結服務。而閉包則是我們使用這個服務的時候才去範例化物件。可以看出閉包是有很多的優勢的。

make

make方法就從容器中出去方法。裡面首先判斷了instances變數中是否有當前以及存在的服務物件,如果有直接返回。如果沒有那麼會通過 call_user_func_array返回一個物件。call_user_func_array的使用可以檢視
PHP 中 call_user_func 的使用

更多PHP相關技術文章,請存取PHP教學欄目進行學習!

以上就是PHP中的相關服務容器與依賴注入的相關解析的詳細內容,更多請關注TW511.COM其它相關文章!