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);
    
    通过配置支持属性和设置器注入 -
    
    <?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 步- 现在,将 actionTestInterface 添加到SiteController
    
    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
    这种方法很方便,因为我们可以在一个地方设置类,其他代码会自动使用新的类。