2.6. Inyección de Dependencias

2.6.1. Propósito

Implementar una arquitectura débilmente acoplada para obtener un código más mantenible, extensible y testeable.

2.6.2. Uso

DatabaseConfiguration se inyecta y DatabaseConnection obtendrá todo lo que necesita de $config. Sin Inyección de Dependencias, la configuración se crearía directamente en DatabaseConnection, lo que no es muy óptimo para testear y extender.

2.6.3. Ejemplos

  • Doctrine2 ORM usa inyección de dependencias e.j. para la configuración que se inyecta en un objeto Connection. Para propósitos de testing, uno puede fácilmente crear un objeto simulado de la configuración e inyectarlo en el Objeto Conexión
  • muchos frameworks ya tienen contenedores para inyección de dependencias que crean objetos a través de una matriz de configuración y los inyecta donde sea necesario (es decir, en Controladores)

2.6.4. Diagrama UML

Alt DependencyInjection UML Diagram

2.6.5. Código

Puedes encontrar el código en GitHub

DatabaseConfiguration.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php

declare(strict_types=1);

namespace DesignPatterns\Structural\DependencyInjection;

class DatabaseConfiguration
{
    public function __construct(
        private string $host,
        private int $port,
        private string $username,
        private string $password
    ) {
    }

    public function getHost(): string
    {
        return $this->host;
    }

    public function getPort(): int
    {
        return $this->port;
    }

    public function getUsername(): string
    {
        return $this->username;
    }

    public function getPassword(): string
    {
        return $this->password;
    }
}

DatabaseConnection.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

declare(strict_types=1);

namespace DesignPatterns\Structural\DependencyInjection;

class DatabaseConnection
{
    public function __construct(private DatabaseConfiguration $configuration)
    {
    }

    public function getDsn(): string
    {
        // this is just for the sake of demonstration, not a real DSN
        // notice that only the injected config is used here, so there is
        // a real separation of concerns here

        return sprintf(
            '%s:%s@%s:%d',
            $this->configuration->getUsername(),
            $this->configuration->getPassword(),
            $this->configuration->getHost(),
            $this->configuration->getPort()
        );
    }
}

2.6.6. Test

Tests/DependencyInjectionTest.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php

declare(strict_types=1);

namespace DesignPatterns\Structural\DependencyInjection\Tests;

use DesignPatterns\Structural\DependencyInjection\DatabaseConfiguration;
use DesignPatterns\Structural\DependencyInjection\DatabaseConnection;
use PHPUnit\Framework\TestCase;

class DependencyInjectionTest extends TestCase
{
    public function testDependencyInjection()
    {
        $config = new DatabaseConfiguration('localhost', 3306, 'domnikl', '1234');
        $connection = new DatabaseConnection($config);

        $this->assertSame('domnikl:1234@localhost:3306', $connection->getDsn());
    }
}