2.6. Injeção de dependência (Dependency Injection)

2.6.1. Objetivo

Implementar uma arquitetura menos acoplada com o objetivo de obter um código mais fácil de testar, de melhor manutenibilidade e mais extensível.

2.6.2. Uso

DatabaseConfiguration é injetado e DatabaseConnection irá receber tudo o que é necessário de $config. Sem a Injeção de Dependência, a configuração seria criada diretamente em DatabaseConnection, o que não é muito bom para testar e extender isto.

2.6.3. Exemplos

  • O ORM Doctrine 2 usa injeção de dependência, por exemplo, para a configuração que é injetada no objeto Connection. Para propósitos de teste, algúem pode facilmente criar um objeto simulado na configuração e injetá-lo no objeto Connection.

  • muitos frameworks já têm contêineres para ID que criam objetos por meio de um array de configuração e os injetam onde necessário (ou seja, nos Controladores)

2.6.4. Diagrama UML

Alt DependencyInjection UML Diagram

2.6.5. Código

Você pode também ver este código no GitHub

DatabaseConfiguration.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\DependencyInjection;
 6
 7class DatabaseConfiguration
 8{
 9    public function __construct(
10        private string $host,
11        private int $port,
12        private string $username,
13        private string $password
14    ) {
15    }
16
17    public function getHost(): string
18    {
19        return $this->host;
20    }
21
22    public function getPort(): int
23    {
24        return $this->port;
25    }
26
27    public function getUsername(): string
28    {
29        return $this->username;
30    }
31
32    public function getPassword(): string
33    {
34        return $this->password;
35    }
36}

DatabaseConnection.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\DependencyInjection;
 6
 7class DatabaseConnection
 8{
 9    public function __construct(private DatabaseConfiguration $configuration)
10    {
11    }
12
13    public function getDsn(): string
14    {
15        // this is just for the sake of demonstration, not a real DSN
16        // notice that only the injected config is used here, so there is
17        // a real separation of concerns here
18
19        return sprintf(
20            '%s:%s@%s:%d',
21            $this->configuration->getUsername(),
22            $this->configuration->getPassword(),
23            $this->configuration->getHost(),
24            $this->configuration->getPort()
25        );
26    }
27}

2.6.6. Teste

Tests/DependencyInjectionTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\DependencyInjection\Tests;
 6
 7use DesignPatterns\Structural\DependencyInjection\DatabaseConfiguration;
 8use DesignPatterns\Structural\DependencyInjection\DatabaseConnection;
 9use PHPUnit\Framework\TestCase;
10
11class DependencyInjectionTest extends TestCase
12{
13    public function testDependencyInjection()
14    {
15        $config = new DatabaseConfiguration('localhost', 3306, 'user', '1234');
16        $connection = new DatabaseConnection($config);
17
18        $this->assertSame('user:1234@localhost:3306', $connection->getDsn());
19    }
20}