Yii - 依賴注入



依賴注入 (DI) 容器是一個知道如何例項化和配置物件的容器。Yii 透過yii\di\Container 類提供 DI 容器。

它支援以下幾種 DI:

  • Setter 和屬性注入
  • PHP 可呼叫注入
  • 建構函式注入
  • 控制器動作注入

DI 容器透過型別提示支援建構函式注入:

class Object1 {
   public function __construct(Object2 $object2) {

   }
}
$object1 = $container->get('Object1');
// which is equivalent to the following:
$object2 = new Object2;
$object1 = new Object1($object2);

屬性和 setter 注入透過配置支援:

<?php
   use yii\base\Object;
   class MyObject extends Object {
      public $var1;
      private $_var2;
      public function getVar2() {
         return $this->_var2;
      }
      public function setVar2(MyObject2 $var2) {
         $this->_var2 = $var2;
      }
   }
   $container->get('MyObject', [], [
      'var1' => $container->get('MyOtherObject'),
      'var2' => $container->get('MyObject2'),
   ]);
?>

對於 PHP 可呼叫注入,容器將使用註冊的 PHP 回撥來構建類的新的例項:

$container->set('Object1', function () {
   $object1 = new Object1(new Object2);
   return $object1;
});
$object1 = $container->get('Object1');

控制器動作注入是一種 DI 型別,其中依賴項使用型別提示宣告。它有助於保持 MVC 控制器輕量級:

public function actionSendToAdmin(EmailValidator $validator, $email) {
   if ($validator->validate($email)) {
      // sending email
   }
}

可以使用yii\db\Container::set()方法註冊依賴項:

<?php
   $container = new \yii\di\Container;
   // register a class name as is. This can be skipped.
   $container->set('yii\db\Connection');
   // register an alias name. You can use $container->get('MyObject')
   // to create an instance of Connection
   $container->set('MyObject', 'yii\db\Connection');
   // register an interface
   // When a class depends on the interface, the corresponding class
   // will be instantiated as the dependent object
   $container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');
   // register an alias name with class configuration
   // In this case, a "class" element is required to specify the class
   $container->set('db', [
      'class' => 'yii\db\Connection',
      'dsn' => 'mysql:host=127.0.0.1;dbname = helloworld',
      'username' => 'vladimir',
      'password' => '12345',
      'charset' => 'utf8',
   ]);
   // register a class with configuration. The configuration
   // will be applied when the class is instantiated by get()
   $container->set('yii\db\Connection', [
      'dsn' => 'mysql:host=127.0.0.1;dbname = helloworld',
      'username' => 'vladimir',
      'password' => '12345',
      'charset' => 'utf8',
   ]);
   // register a PHP callable
   // The callable will be executed each time when $container->get('db') is called
   $container->set('db', function ($container, $params, $config) {
      return new \yii\db\Connection($config);
   });
   // register a component instance
   // $container->get('pageCache') will return the same instance each time when it 
      //is called
   $container->set('pageCache', new FileCache);
?>

使用 DI

步驟 1 - 在components資料夾中建立一個名為MyInterface.php的檔案,內容如下。

<?php
   namespace app\components;
   interface MyInterface {
      public function test();
   }
?>

步驟 2 - 在 components 資料夾中,建立兩個檔案。

First.php -

<?php
   namespace app\components;
   use app\components\MyInterface;
   class First implements MyInterface {
      public function test() {
         echo "First class <br>";
      }
   }
?>

Second.php -

<?php
   app\components;
   use app\components\MyInterface;
      class Second implements MyInterface {
      public function test() {
         echo "Second class <br>";
      }
   }
?>

步驟 3 - 現在,向 SiteController 新增一個actionTestInterface

public function actionTestInterface() {
   $container = new \yii\di\Container();
   $container->set
      ("\app\components\MyInterface","\app\components\First");
   $obj = $container->get("\app\components\MyInterface");
   $obj->test(); // print "First class"
   $container->set
      ("\app\components\MyInterface","\app\components\Second");
   $obj = $container->get("\app\components\MyInterface");
   $obj->test(); // print "Second class"
}

步驟 4 - 訪問https://:8080/index.php?r=site/test-interface,您應該看到以下內容。

Using DI

這種方法很方便,因為我們可以在一個地方設定類,其他程式碼將自動使用新的類。

廣告