joomla/di
PSR-11 compatible dependency injection (IoC) container from the Joomla Framework. Provides a powerful, flexible DI solution for PHP 8.1+ applications, with Composer installation and support for stable/unstable releases.
Start by installing the package via Composer: composer require joomla/di. Then, create a Container instance early in your app’s bootstrap (e.g., before application instantiation), and register service providers to populate it. The container implements PSR-11’s ContainerInterface, so basic usage ($container->get($id), $container->has($id)) feels familiar. A minimal first use case is defining a database connection as a shared service:
$container = new Joomla\DI\Container;
$container->share('db', fn($c) => new PDO('mysql:dbname=test', 'user', 'pass'));
$db = $container->get('db'); // Same instance on next $container->get('db')
Check the overview.md in docs for detailed examples and the README.md for core API highlights.
Service Providers: Organize related services into classes implementing ServiceProviderInterface and register them with registerServiceProvider(). This keeps bootstrapping clean and modular.
Hierarchical Containers: Use createChild() to override services for specific scopes (e.g., per-request or per-controller) without polluting the root container. Parent containers provide fallback resolution for missing dependencies.
Auto-Wiring: Pass interfaces or class names to get(), and the container will instantiate them automatically if their dependencies are resolvable — works well with type-hinted constructors.
Resource Modes: Prefer share() for singletons (e.g., Doctrine EM, HTTP clients). Use protect() for critical services (e.g., config) to prevent accidental overwrites in child containers.
Extending Services: Use extend() to decorate or modify existing services (e.g., logging middleware around a service):
$container->share('logger', fn() => new SimpleLogger());
$container->extend('logger', fn($logger, $c) => new BufferedLogger($logger));
Delegation: Nest external PSR-11 containers as parents to extend them with Joomla DI features (e.g., aliases, protected sharing).
Default Mode is Not Shared: Using set() with a callable returns a new instance on every get() unless you explicitly call share(). This trips up newcomers expecting singleton behavior.
Protected Overrides Throw: Attempting to set() a key that’s already protected throws OutOfBoundsException. Use isProtected() before dynamic overrides (e.g., in testing or plugins).
Callable Signature Matters: Factories receive the container instance as their only argument — don’t rely on closure $this binding or variadic args. Use named closures or classes if argument injection is needed.
Child Scope Isolation: Child containers inherit but don’t copy parent resources — changes to parent resources (e.g., via set()) after child creation won’t affect the child unless you rebuild the hierarchy.
Alias Performance: Aliases resolve at get() time via lookup chain. For hot paths, prefer direct service IDs; avoid chaining long alias chains in performance-critical code.
Debug Tip: Use $container->peek($id) to inspect a resource’s current state (shared/protected, factory vs value) without triggering re-resolution — helpful for diagnosing unexpected reuse or recreation.
How can I help you explore Laravel packages today?