Yii Tutorial on Yii Dependency Injection

a di(dependency injection) container is an object that knows how to instantiate and configure objects. yii provides the di container via the yii\di\container class.

it supports the following kinds of di −

  • setter and property injection
  • php callable injection
  • constructor injection
  • controller action injection

the di container supports constructor injection with the help of type hints −

class object1 {
   public function __construct(object2 $object2) {

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

property and setter injections are supported through configurations −

<?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 case of the php callable injection, the container will use a registered php callback to build new instances of a class −

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

controller action injection is a type of di where dependencies are declared using the type hints. it is useful for keeping the mvc controllers slim light-weighted and slim −

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

using the di

step 1 − inside the components folder create a file called myinterface.php with the following code.

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

step 2 − inside the components folder, create two files.

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 − now, add an actiontestinterface to the 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 − go to http://localhost:8080/index.php?r=site/test-interface you should see the following.

using di

this approach is convenient as we can set classes in one place and other code will use new classes automatically.