aura/di
Aura.Di is a PSR-11 dependency injection container for PHP 8+, supporting serializable containers, constructor and setter injection, interface/trait awareness, and configuration inheritance. Lightweight, standards-friendly, and flexible for complex apps.
composer require aura/di. Requires PHP 8.0+.ContainerBuilder, then build your container with configuration classes (or use newInstance() for quick setup).$di->set() and $di->lazyNew() before locking the container — prefer lazy construction during configuration.$di->set('db', $di->lazyNew(Database::class, [
'dsn' => 'mysql:host=localhost;dbname=test',
'user' => 'root',
'pass' => '',
]));
$db = $di->get('db'); // Returns same instance on subsequent calls
get()/newInstance(), so organize all config upfront.ContainerBuilder + Config Classes: Create one or more classes implementing ContainerConfig (or extending AbstractConfig) to centralize service definitions and param overrides. Example:
class AppConfig extends AbstractConfig {
public function define() {
$this->set('logger', $this->lazyNew(Logger::class));
}
public function modify() {
$logger = $this->get('logger');
$logger->setLevel('debug');
}
}
$di = $builder->newConfiguredInstance([AppConfig::class]);
#[Inject] for constructor/setter injection:
class Service {
#[Inject]
public function setDb(Database $db) { ... }
}
Enable via ContainerBuilder::useAttributes(true) — avoids verbose param definitions.newCompiledInstance() with ClassScannerConfig after scanning your codebase (vendor/bin/auradi scan). Serialize the compiled container to OPcache or file — ideal for production.lazyNew()->withContext(Blueprint::class, [...]) instead of repeating full trees — keeps config DRY.$di->autoResolve() (or rely on default) to resolve missing params via type-hinted constructors — but prefer explicit config for clarity and control.get() or newInstance(), any further set(), params[] modification, or lazySet() throws an exception. Always configure fully before resolving.newInstance() locks the container even inside config classes — use lazyNew() during definition, newInstance() only when you need an immediate, non-shared instance.params arrays, not direct new calls, during config:
// Good
$di->params[SomeService::class]['dependency'] = $di->lazyNew(Dep::class);
// ❌ Avoid (locks too early)
$di->set('someService', new SomeService(new Dep()));
params and setters from traits and interfaces are inherited automatically — useful for cross-cutting concerns (e.g., LoggerAwareInterface).Container::getServiceDefinition($name) to inspect how a service was defined — invaluable when troubleshooting injection mismatches.withContext() works only with lazyNew(), not newInstance(). For production, ensure context paths are shallow — deeply nested context trees can obscure logic.get() throughout app code (instead of injecting the container into a few well-defined factories/bootstrap services) is discouraged.How can I help you explore Laravel packages today?