georgeff / container
A lightweight dependency injection container implementing PSR-11
Requires
- php: ^8.2
- psr/container: ^2.0
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
- squizlabs/php_codesniffer: ^3.11
README
A lightweight dependency injection container implementing PSR-11.
Installation
composer require georgeff/container
Usage
Registering Definitions
Register a definition by providing an ID and a callable factory. The container instance is passed to the factory.
use Georgeff\Container\Container; $container = new Container(); $container->add('database', function (Container $container) { return new DatabaseConnection('localhost', 'mydb'); });
Shared Definitions
Shared definitions are resolved once and the same instance is returned on subsequent calls.
$container->addShared('database', function (Container $container) { return new DatabaseConnection('localhost', 'mydb'); }); // Or pass true as the third argument to add() $container->add('database', function (Container $container) { return new DatabaseConnection('localhost', 'mydb'); }, true);
Resolving Definitions
$db = $container->get('database');
Aliases
Aliases allow you to resolve a definition by an alternate name, useful for binding interfaces to implementations.
$container->addShared(DatabaseConnection::class, function (Container $container) { return new DatabaseConnection('localhost', 'mydb'); }); $container->addAlias(DatabaseConnection::class, ConnectionInterface::class); // Resolves the DatabaseConnection definition $db = $container->get(ConnectionInterface::class);
Resolution Hooks
Hooks allow you to observe or react to service resolution. Four hooks are available: global pre, service-specific pre, service-specific post, and global post. When multiple hooks are registered they fire in that order — global pre first, global post last.
Global pre-resolution — fires on every get() call, including cache hits for shared services:
$container->onResolving(function (string $id): void { echo "Resolving: $id"; });
Service-specific pre-resolution — fires only when the given ID is resolved:
$container->onResolvingId('database', function (string $id): void { echo "Resolving database"; });
Service-specific post-resolution — fires after the factory runs for the given ID; does not fire on cache hits:
$container->afterResolvedId('database', function (string $id, mixed $instance): void { echo "Resolved database"; });
Global post-resolution — fires after the factory runs for any service; does not fire on cache hits:
$container->afterResolved(function (string $id, mixed $instance): void { echo "Resolved: $id"; });
All hooks receive the canonical ID after alias resolution, not the alias used to call get(). Multiple hooks of the same type can be registered and all will fire in registration order.
Checking for Definitions
$container->has('database'); // true $container->has('nonexistent'); // false
Exceptions
DefinitionNotFoundException— thrown when getting a definition that does not exist or aliasing a non-existing definition. Implements PSR-11NotFoundExceptionInterface.CircularDependencyException— thrown when a circular dependency is detected during resolution. Implements PSR-11ContainerExceptionInterface.ContainerException— thrown when an error occurs during definition resolution. Implements PSR-11ContainerExceptionInterface.
License
MIT