Yii - 依赖注入

DI(依赖注入)容器是一个知道如何实例化和配置对象的对象。Yii 通过 yii\di\Container 类 提供 DI 容器。

它支持以下类型的 DI −

  • Setter 和属性注入
  • PHP 可调用注入
  • 构造函数注入
  • 控制器动作注入

DI 容器借助类型提示支持构造函数注入 −

class Object1 {
    public function __construct(Object2 $object2) {
    
    }
}
$object1 = $container->get('Object1');
// 相当于以下内容:
$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
   }
}

You can use the yii\db\Container::set() method to register dependencies −

<?php
    $container = new \yii\di\Container;
    // 按原样注册一个类名。这可以跳过。
    $container->set('yii\db\Connection');
    // 注册一个别名。您可以使用 $container->get('MyObject')
    // 创建 Connection 的实例
    $container->set('MyObject', 'yii\db\Connection');
    // 注册一个接口
    // 当类依赖于接口时,相应的类
    // 将被实例化为依赖对象
    $container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');
    // 使用类配置注册一个别名
    // 在这种情况下,需要一个"class"元素来指定类
    $container->set('db', [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=127.0.0.1;dbname = helloworld',
    'username' => 'vladimir',
    'password' => '12345',
    'charset' => 'utf8',
    ]);
    // 使用配置注册一个类。该配置
    // 将在通过 get() 实例化类时应用
    $container->set('yii\db\Connection', [
    'dsn' => 'mysql:host=127.0.0.1;dbname = helloworld',
    'username' => 'vladimir',
    'password' => '12345',
    'charset' => 'utf8',
    ]);
    // 注册一个 PHP 可调用函数
    // 每次调用 $container->get('db') 时,都会执行该可调用函数
    $container->set('db', function ($container, $params, $config) {
    return new \yii\db\Connection($config);
    });
    // 注册一个组件实例
    // $container->get('pageCache') 每次被调用时都会返回相同的实例
    //被调用
    $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 − 转到 http://localhost:8080/index.php?r=site/test-interface 您应该会看到以下内容。

使用 DI

这种方法很方便,因为我们可以在一个地方设置类,其他代码将自动使用新类。