2.6. Dependency Injection
2.6.1. Purpose
To implement a loosely coupled architecture in order to get bettertestable, maintainable and extendable code.
2.6.2. Usage
DatabaseConfiguration
gets injected and DatabaseConnection
will get all that itneeds from $config
. Without DI, the configuration would be createddirectly in DatabaseConnection
, which is not very good for testing andextending it.
2.6.3. Examples
- The Doctrine2 ORM uses dependency injection e.g. for configurationthat is injected into a
Connection
object. For testing purposes,one can easily create a mock object of the configuration and injectthat into theConnection
object - Symfony and Zend Framework 2 already have containers for DI thatcreate objects via a configuration array and inject them where needed(i.e. in Controllers)
2.6.4. UML Diagram
2.6.5. Code
You can also find this code on GitHub
DatabaseConfiguration.php
- <?php
- namespace DesignPatterns\Structural\DependencyInjection;
- class DatabaseConfiguration
- {
- /**
- * @var string
- */
- private $host;
- /**
- * @var int
- */
- private $port;
- /**
- * @var string
- */
- private $username;
- /**
- * @var string
- */
- private $password;
- public function __construct(string $host, int $port, string $username, string $password)
- {
- $this->host = $host;
- $this->port = $port;
- $this->username = $username;
- $this->password = $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
- <?php
- namespace DesignPatterns\Structural\DependencyInjection;
- class DatabaseConnection
- {
- /**
- * @var DatabaseConfiguration
- */
- private $configuration;
- /**
- * @param DatabaseConfiguration $config
- */
- public function __construct(DatabaseConfiguration $config)
- {
- $this->configuration = $config;
- }
- 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
- <?php
- 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->assertEquals('domnikl:1234@localhost:3306', $connection->getDsn());
- }
- }