https://github.com/quantaphp/container
Minimalist dependency injection container implementing Psr-11
https://github.com/quantaphp/container
container dependency-injection psr-11
Last synced: about 1 month ago
JSON representation
Minimalist dependency injection container implementing Psr-11
- Host: GitHub
- URL: https://github.com/quantaphp/container
- Owner: quantaphp
- License: mit
- Created: 2018-06-15T07:52:01.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2022-09-13T12:08:02.000Z (over 3 years ago)
- Last Synced: 2025-07-13T22:08:36.973Z (7 months ago)
- Topics: container, dependency-injection, psr-11
- Language: PHP
- Homepage: https://github.com/quantaphp/container/
- Size: 83 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Quanta Psr-11 container
This package provides a minimalist dependency injection container implementing [Psr-11](https://www.php-fig.org/psr/psr-11/).
The goal is to implement a container working out of the box with minimal configuration, implementing interface aliasing and a
basic autowiring mechanism.
- [Getting started](#getting-started)
- [Basic usage](#basic-usage)
- [Interface aliasing](#interface-aliasing)
- [Autowiring](#autowiring)
## Getting started
**Require** php >= 7.4
**Installation** `composer require quanta/container`
**Run tests** `php ./vendor/bin/phpunit`
**Testing a specific php version using docker:**
- `docker build . --build-arg PHP_VERSION=7.4 --tag quanta/container/tests:7.4`
- `docker run --rm quanta/container/tests:7.4`
## Basic usage
- container entries are defined using any iterable as long as keys can be casted as strings
- any non callable value is returned as is like an associative array
- any callable value is treated as a factory building the associated value (the results are cached so
the callable is run only once and the same value is returned on every `->get()` call)
```php
'value',
SomeClass::class => fn ($container) => new SomeClass(
$container->get(SomeDependency::class),
),
SomeDependency::class => fn () => new SomeDependency,
'throwing' => function () {
throw new Exception('some exception');
},
]);
// true
$container instanceof Psr\Container\ContainerInterface;
$container->has('id');
$container->has(SomeClass::class);
$container->has(SomeDependency::class);
$container->has('throwing');
$container->get('id') === 'value';
$container->get(SomeClass::class) == new SomeClass(new SomeDependency);
$container->get(SomeDependency::class) == new SomeDependency;
$container->get(SomeClass::class) === $container->get(SomeClass::class);
$container->get(SomeDependency::class) === $container->get(SomeDependency::class);
$container->get(SomeClass::class)->dependency === $container->get(SomeDependency::class);
// false
$container->has('not.defined');
// throws Quanta\Container\NotFoundException
try {
$container->get('not.defined');
} catch (Quanta\Container\NotFoundException $e) {
// 'No 'not.defined' entry defined in the container'
echo $e->getMessage() . "\n";
}
// throws Quanta\Container\ContainerException with the caught exception as previous
try {
$container->get('throwing');
} catch (Quanta\Container\ContainerException $e) {
// 'Cannot get 'throwing' from the container: factory has thrown an uncaught exception'
echo $e->getMessage() . "\n";
// 'some exception'
echo $e->getPrevious()->getMessage() . "\n";
}
```
## Interface aliasing
- interface names associated to strings are treated as aliases
```php
// class definitions
interface SomeInterface
{
}
final class SomeImplementation implements SomeInterface
{
}
// container configuration
$container = new Quanta\Container([
SomeInterface::class => SomeImplementation::class,
SomeImplementation::class => fn () => new SomeImplementation,
]);
// true
$container->has(SomeInterface::class);
$container->has(SomeImplementation::class);
$container->get(SomeInterface::class) == new SomeImplementation;
$container->get(SomeImplementation::class) == new SomeImplementation;
$container->get(SomeInterface::class) === $container->get(SomeInterface::class);
$container->get(SomeInterface::class) === $container->get(SomeImplementation::class);
$container->get(SomeImplementation::class) === $container->get(SomeImplementation::class);
```
## Autowiring
The container will try to build instances of non defined classes using simple rules to infer constructor parameter values:
- when the type of a parameter is a defined interface name, its value is retrieved from the container
- when the type of a parameter is a class name, its value is retrieved from the container (and also autowired if not defined)
- when the type of a parameter is not an interface/class name, its default value is used if present
- null is used as a fallback when the parameter allows null
- a `Quanta\Container\ContainerException` is thrown when:
- no value can be infered for a parameter (not an interface/class name as type, no default value, not allowing null)
- trying to infer the value of a parameter with union/intersection type, without default value, not allowing null (php 8.0/8.1)
- trying to autowire an abstract class or a class with protected/private constructor
- the `->has()` method returns true for any existing classes
- the objects built through autowiring are cached
A factory must be defined when more control over the class instantiation is needed.
```php
SomeImplementation::class,
]);
// true
$container->has(SomeInterface::class);
$container->has(SomeImplementation::class);
$container->has(UndefinedClass::class);
$container->has(AnotherUndefinedClass::class);
$container->get(SomeInterface::class) == new SomeImplementation;
$container->get(SomeImplementation::class) == new SomeImplementation;
$container->get(UndefinedClass::class) == new UndefinedClass(new SomeImplementation, new AnotherUndefinedClass, null);
$container->get(AnotherUndefinedClass::class) == new AnotherUndefinedClass;
$container->get(SomeInterface::class) === $container->get(SomeInterface::class);
$container->get(SomeInterface::class) === $container->get(SomeImplementation::class);
$container->get(SomeImplementation::class) === $container->get(SomeImplementation::class);
$container->get(UndefinedClass::class) === $container->get(UndefinedClass::class);
$container->get(AnotherUndefinedClass::class) === $container->get(AnotherUndefinedClass::class);
$container->get(UndefinedClass::class)->dependency1 === $container->get(SomeInterface::class);
$container->get(UndefinedClass::class)->dependency2 === $container->get(AnotherUndefinedClass::class);
$container->get(UndefinedClass::class)->dependency3 === null;
$container->get(UndefinedClass::class)->dependency4 === 'test';
```