Yii - Dependency Injection

Un contenitore DI (dependency injection) è un oggetto che sa come istanziare e configurare gli oggetti. Yii fornisce il contenitore DI tramiteyii\di\Container class.

Supporta i seguenti tipi di DI:

  • Setter e iniezione di proprietà
  • Iniezione chiamabile PHP
  • Iniezione nel costruttore
  • Iniezione di azioni del controller

Il contenitore DI supporta l'inserimento del costruttore con l'aiuto di suggerimenti sul tipo -

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

Le iniezioni di proprietà e setter sono supportate tramite configurazioni:

<?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'),
   ]);
?>

In caso dell'iniezione chiamabile PHP, il contenitore utilizzerà un callback PHP registrato per creare nuove istanze di una classe -

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

L'iniezione di azioni del controller è un tipo di DI in cui le dipendenze vengono dichiarate utilizzando i suggerimenti sul tipo. È utile per mantenere i controller MVC sottili, leggeri e sottili -

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

Puoi usare il file yii\db\Container::set() metodo per registrare le dipendenze -

<?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);
?>

Utilizzando il DI

Step 1 - All'interno del components cartella crea un file chiamato MyInterface.php con il seguente codice.

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

Step 2 - All'interno della cartella dei componenti, crea due file.

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>";
      }
   }
?>

Step 3 - Ora aggiungi un file actionTestInterface al 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"
}

Step 4 - Vai a http://localhost:8080/index.php?r=site/test-interface dovresti vedere quanto segue.

Questo approccio è conveniente in quanto possiamo impostare le classi in un posto e l'altro codice utilizzerà automaticamente le nuove classi.