首頁  >  文章  >  後端開發  >  PHP中的服務容器與依賴注入的思想

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

藏色散人
藏色散人轉載
2019-11-05 13:44:462088瀏覽

依賴注入

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

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

<?php
/**
 * 定义了一个消息类
 * Class Message 
 */
class  Message{
  public function seed()
  {
      return &#39;seed email&#39;;
  }
}
/*
 * 订单产生的时候 需要发送消息
 */
class Order{
    protected $messager = &#39;&#39;;
    function __construct()
    {
        $this->messager = new Message();
    }
    public function seed_msg()
    {
        return $this->messager->seed();
    }
}
$Order = new Order();
$Order->seed_msg();

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

<?php
/**
 * 为了约束我们先定义一个消息接口
 * Interface Message
 */
interface  Message{
  public function seed();
}
/**
 * 有一个发送邮件的类
 * Class SeedEmail
 */
class SeedEmail implements Message
{
    public function seed()
    {
        return  &#39;seed email&#39;;
        // TODO: Implement seed() method.
    }
}
/** 
 *新增一个发送短信的类
 * Class SeedSMS
 */
class SeedSMS implements Message
{
    public function seed()
    {
        return &#39;seed sms&#39;;
        // TODO: Implement seed() method.
    }
}
/*
 * 订单产生的时候 需要发送消息
 */
class Order{
    protected $messager = &#39;&#39;;
    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();

這樣我們就實現了依賴注入的思路,是不是很方便擴展了。

服務容器

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

<?php
/**
 * 为了约束我们先定义一个消息接口
 * Interface Message
 */
interface  Message{
    public function seed();
}
/**
 * 有一个发送邮件的类
 * Class SeedEmail
 */
class SeedEmail implements Message
{
    public function seed()
    {
        return  &#39;seed email&#39;;
        // TODO: Implement seed() method.
    }
}
/**
 *新增一个发送短信的类
 * Class SeedSMS
 */
class SeedSMS implements Message
{
    public function seed()
    {
        return &#39;seed sms&#39;;
        // 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(&#39;SMS&#39;,function (){
     return   new  SeedSMS();
});
//将发送邮件注册绑定到工厂
$message->bind(&#39;EMAIL&#39;,function (){
   return new  SeedEmail();
});
//需要发送短信的时候
$SMS  = $message->make(&#39;SMS&#39;);
$SMS->seed();

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

bind是綁定服務物件到容器中。 make則是從容器中取出物件。

bind

在bind方法中需要傳入一個 concrete 我們可以傳入一個實例物件或是一個閉包函數。

可以看到我這全使用的是閉包函數,其實也可以這樣寫

$sms = new  SeedSMS();
$message->bind(&#39;SMS&#39;,$sms);

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

make

make方法就從容器中出去方法。裡面首先判斷了instances變數中是否有目前以及存在的服務對象,如果有直接回傳。如果沒有那麼會透過 call_user_func_array回傳一個物件.

更多的PHP相關知識,請造訪PHP中文網

以上是PHP中的服務容器與依賴注入的思想的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除