The PHP bug tracker application ships with a simplistic dependency injection container which can create services and retrieves configuration values.
Services are one of the more frequently used objects everywhere across the application. For example, service for database access, utility service for uploading files, data generators, API clients, and similar.
Dependencies between classes are injected using either constructor, or via a method call such as setter.
class Repository
{
private $pdo;
public function __construct(\PDO $pdo)
{
$this->pdo = $pdo;
}
public function getData(): array
{
return $this->pdo->query("SELECT * FROM table")->fetchAll();
}
}
$pdo = new \PDO(
'mysql:host=localhost;dbname=bugs;charset=utf8', 'nobody', 'password',
[
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
]
);
$repository = new Repository($pdo);
$data = $repository->getData();
The $pdo
object in the example is a dependency which is injected via the
constructor.
Dependency injection container further provides a more efficient creation of such dependencies and services:
$container = require_once __DIR__.'/../config/container.php';
$data = $container->get(Repository::class)->getData();
Configuration parameters include infrastructure configuration (database credentials...) and application level configuration (directories locations...).
// config/parameters.php
return [
'parameter_key' => 'value',
// ...
];
Which can be retrieved by the container:
$value = $container->get('parameter_key');
Each service class is manually defined:
// config/container.php
// New container initialization with configuration parameters defined in a file.
$container = new Container(include __DIR__.'/parameters.php');
// Services are then defined using callables with a container argument $c.
// Service with constructor arguments
$container->set(App\Foo::class, function ($c) {
return new App\Foo($c->get(App\Dependency::class));
});
// Service with a setter method
$container->set(App\Foo\Bar::class, function ($c) {
$object = new App\Foo\Bar($c->get(App\Dependency::class));
$object->setFoobar('argument');
return $object;
});
// Dependencies can be service classes or configuration parameters
$container->set(App\Foo\Bar::class, function ($c) {
return new App\Foo\Bar(
// Configuration parameter
$c->get('parameter_key'));
// Calling method from another service
$c->get(App\Dependency::class)->methodName();
);
});
// Service with no dependencies
$container->set(App\Dependency::class, function ($c) {
return new App\Dependency();
});
return $container;