2.6. Dependency Injection

2.6.1. Scopo

Implementare un’architettura con basso accoppiamento affinchè il codice sia meglio testabile, manutenibile ed estensibile.

2.6.2. Utilizzo

DatabaseConfiguration è iniettata e DatabaseConnexion otterrà tutto quello di cui necessita da $config. Senza DI, la configurazione sarebbe stata creata direttamente dentro DatabaseConnexion la quale non sarebbe stata facile da testare ed estendere.

2.6.3. Esempi

  • L’ORM Doctrine2 utilizza questo pattern per la configurazione che è iniettata nell’oggetto Connection. Per il testing, si può facilmente creare un oggetto mock di configurazione iniettandolo nell’oggetto Connection.

  • Molti framework possiedono già dei contenitori che usano DI per creare oggetti tramite configurazioni sottoforma di array e iniettarle quando necessario (ad esempio i Controller)

2.6.4. Diagramma UML

Alt DependencyInjection UML Diagram

2.6.5. Codice

Potete trovare questo codice anche su 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. Test

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}