What it is
PHP-DI is a dependency injection container with autowiring, PHP-based configuration and support for the PSR-11 container interface.
The container resolves constructor dependencies by type hint. Definitions cover interfaces, scalars and factories where reflection is not enough.
Installation
composer require php-di/php-diGetting started
The smallest useful thing you can do with it, and what each part means.
php
<?php
use function DI\{create, get, autowire, factory};
$builder = new DI\ContainerBuilder();
$builder->addDefinitions([
// Interfaces need an explicit binding — reflection cannot guess.
BookRepository::class => autowire(DoctrineBookRepository::class),
// Scalars must be provided.
'db.dsn' => 'pgsql:host=localhost;dbname=app',
PDO::class => factory(fn ($c) => new PDO(
$c->get('db.dsn'),
options: [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
)),
]);
$builder->enableCompilation(__DIR__ . '/var/cache'); // production
$container = $builder->build();
$service = $container->get(BookService::class); // constructor autowiredAdvanced usage
Where the library earns its place over a simpler alternative.
php
<?php
return [
BookRepository::class => DI\decorate(function ($previous, $container) {
return new CachingBookRepository($previous, $container->get(Cache::class));
}),
// Attribute injection for properties (must be enabled explicitly).
// #[Inject] private LoggerInterface $logger;
];
// Layer environment overrides on top of the base definitions.
$builder->addDefinitions('config/common.php');
if ($env === 'test') {
$builder->addDefinitions('config/test.php'); // later wins
}Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Entry cannot be resolved: parameter $x has no type
- Autowiring needs type hints. Add one, or define the parameter explicitly.
- Changes to definitions have no effect
- Compiled definitions are cached. Clear the compilation directory after changing them.
Best practices
- Enable compilation in production; reflection on every request is a real cost.
- Bind interfaces to implementations explicitly — autowiring cannot resolve them.
- Prefer constructor injection over attribute or property injection.
- Type-hint Psr\Container\ContainerInterface if you must accept the container at all.
Background
Why it exists, and what it was reacting to.
PHP-DI made autowiring mainstream in PHP frameworks that lack their own container, using reflection on constructor type hints so most classes need no registration at all.
