scruwi / container
PSR-11 Container implementation
README
It's my own implementation PSR-11 Container Interface.
Installation
composer require scruwi/container
Init
$container = new Container([ new ClassResolver(['App\\Namespace1', 'App\\Namespace2']), new ParameterResolver(['param1' => true, 'param2' => 'string']), new DefinitionResolver([Definition1:class, Definition2:class]), ]);
Resolvers
ClassResolver
- defines namespaces, that are allowed to autowireParameterResolver
- defines scalar parameters, that can be set to constructorsDefinitionResolver
- defines paths to definitions
You can implement your resolvers in a project if you need them. Look at the Interfaces
namespace.
ClassResolver
Only classes from defined namespaces can be autowired.
ParameterResolver
Typical usage:
$rootParameters = ['param1' => true, 'param2' => 'string']; $classSpecificParameters = [SpecificClass::class => ['param1' => false]]; $resolver = ParameterResolver($rootParameters, $classSpecificParameters);
Expected behaviour:
class SomeClass { public function __construct(bool $param1) { /* $param1 === true */ } }
class SpecificClass { public function __construct(bool $param1) { /* $param1 === false */ } }
Parameter with default value does not have to be resolved by the config:
class SpecificClass { public function __construct(bool $param0 = 'default') { /* $param0 === 'default' */ } }
You can create a specific resolver in your way and use it in your project. Just implement ParameterResolverInterface
and specify it during container construct.
DefinitionResolver
Attach definitions to container.
Definition, there is no more than a factory that creates an object in a specific way. There is one
specific ReflectionClassDefinition
that constructs classes by their reflections. All autowired classes use that factory
to create their object.
You should create as many definitions in your project as you need and specify them during container construct or attach
them later by $container->addDefinition()
method. Any definition must implement DefinitionInterface
.
Typical definition class looks like this:
class ExampleDefinition implements DefinitionInterface { public static function getId(): string { return ExampleClass::class; } public function __invoke(Container $container, ParameterResolver $resolver, BuildContext $context): object { return new ExampleClass(); } }
You can fetch some default parameters from the ParameterResolver:
public function __invoke(Container $container, ParameterResolver $resolver, BuildContext $context): object { $param1 = $resolver->resolve('param1', ExampleClass::class); return new ExampleClass($param1); }
Also, you can find out from which context it was called. It may be useful for autowire interfaces:
class InterfaceDefinition implements DefinitionInterface { public function getId(): string { return SomeInterface::class; } public function __invoke(Container $container, ParameterResolver $resolver, BuildContext $context): object { if ($context->getTargetClass() === ClassWithInterfaceDependency::class) { return new SomeClassImplementsInterface2(); } return new SomeClassImplementsInterface1(); } }
Exceptions
NotFoundExceptionInterface
- for an unknown entryContainerExceptionInterface
- for all common exceptions in the containerCircularReferencesException
- there is a special exception for circular references in the container