Yii - injeção de dependência
Um contêiner DI (injeção de dependência) é um objeto que sabe como instanciar e configurar objetos. Yii fornece o contêiner DI por meio doyii\di\Container class.
Ele suporta os seguintes tipos de DI -
- Setter e injeção de propriedade
- Injeção de PHP chamável
- Injeção de construtor
- Injeção de ação do controlador
O contêiner DI suporta injeção de construtor com a ajuda de dicas de 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);
As injeções de propriedade e setter são suportadas por meio de configurações -
<?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'),
]);
?>
No caso da injeção que pode ser chamada de PHP, o contêiner usará um retorno de chamada PHP registrado para construir novas instâncias de uma classe -
$container->set('Object1', function () {
$object1 = new Object1(new Object2); return $object1;
});
$object1 = $container->get('Object1');
A injeção de ação do controlador é um tipo de DI onde as dependências são declaradas usando as dicas de tipo. É útil para manter os controladores MVC finos, leves e finos -
public function actionSendToAdmin(EmailValidator $validator, $email) {
if ($validator->validate($email)) {
// sending email
}
}
Você pode usar o yii\db\Container::set() método para registrar dependências -
<?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);
?>
Usando o DI
Step 1 - Dentro do components pasta cria um arquivo chamado MyInterface.php com o seguinte código.
<?php
namespace app\components;
interface MyInterface {
public function test();
}
?>
Step 2 - Dentro da pasta de componentes, crie dois arquivos.
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 - Agora, adicione um actionTestInterface para o 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 - Vá para http://localhost:8080/index.php?r=site/test-interface você deve ver o seguinte.
Essa abordagem é conveniente, pois podemos definir classes em um lugar e outro código usará novas classes automaticamente.