wart / wart
Extends the Pimple dependency injection container and provides auto class resolving, instantiation and (constructor) injection
Requires
- pimple/pimple: 2.*
Requires (Dev)
This package is not auto-updated.
Last update: 2024-04-23 14:11:26 UTC
README
Extends the Pimple dependency injection container and provides auto class resolving, instantiation and (constructor) injection
Synopsis
<?php namespace Foo\Bar; class Baz { public function hello() { echo "Hello from baz\n"; } } class Bla { protected $baz; public function __construct(Baz $baz) { $this->baz = $baz; } public function hello() { $this->baz->hello(); echo "Hello from bla\n"; } } $container = new Wart; $container['\Foo\Bar\Baz']->hello(); # prints "Hello from baz\n" $container['\Foo\Bar\Bla']->hello(); # prints "Hello from baz\nHello from bla\n"
Installation
composer.phar require wart/wart "*"
Auto resolving class instances
Auto resolving is per default enabled. It enables the magic of instantiating a class by merely naming them as a container key:
<?php $container['\Foo\Bar\Baz']->hello();
Auto resolving can be disabled by either setting the container key manually before fetching it or by constructor parameter
<?php // auto resolving only works on non existing keys! $container = new Wart; $container['\Foo\Bar\Baz'] = 'bla'; echo $container['\Foo\Bar\Baz']; # still "bla" // disable on construct $container = new Wart(array(), array('autoResolve' => false)); // disable later on $container->setAutoResolve(false); // this will not work anymore (unless it has been set manually) echo $container['\Foo\Bar\Baz'];
Aliases
Aliases allow to map service interface to actual implementation:
$container->setAliases(['\Foo\Bar\BazInterface' => '\Foo\Bar\Baz']); $container['\Foo\Bar\BazInterface']; # returns Baz
Aliases can be set with setAliases
or can be passed to the Wart
constructor:
$container = new \Wart([], [ 'aliases' => [ '\Foo\Bar\BazInterface' => '\Foo\Bar\Baz' ] ]);
Additional namespaces
Additional namespaces can be passed to the Wart
constructor:
<?php $container = new Wart(array(), array('namespaces' => array('\Foo', '\Foo\Bar'))); $container['Baz']->hello(); # checks for \Baz and \Foo\Baz and \Foo\Bar\Baz - in that order!
Or set (replaced!) later:
<?php $container = new Wart; $container->setNamespaces(array('\Foo', '\Foo\Bar')); $container['Baz']->hello(); # checks for \Baz and \Foo\Baz and \Foo\Bar\Baz - in that order!
Mind that the order matters!
Creating and auto-registering class instances manually
With auto resolving disabled, the class instances can be pre-generated:
<?php $container = new Wart(array(), array('autoResolve' => false)); $container['\Foo\Bar\Baz']->hello(); # would throw and exception -> key does not exist $instance = $container->create('\Foo\Bar\Baz'); $instance->hello(); $container['\Foo\Bar\Baz']->hello(); # now the key exists
The create
method immediately creates an instance. If you just want to pre-register an instance for later key usage, use autoRegister
:
<?php $container = new Wart(array(), array('autoResolve' => false)); $container['\Foo\Bar\Baz']->hello(); # would throw and exception -> key does not exist $container->autoRegister('\Foo\Bar\Baz'); # does not return anything $container['\Foo\Bar\Baz']->hello(); # now the key exists
Additional constructor parameters
To use additional constructor parameters, you can set them with the createArgs
parameter or with the setCreateArgs
method
<?php namespace Foo\Bar; class Baz { protected $param; public function __construct($param) { $this->param = $param; } public function hello() { echo "Hello {$this->param}\n"; } } class Bla { protected $param; public function __construct(Baz $baz, $param) { $this->param = $param; } public function hello() { echo "Hello {$this->param}\n"; } } class Yadda { protected $scalar; public function __construct(Baz $baz, $scalar, Bla $bla) { $this->scalar = $scalar; } public function hello() { echo "Hello {$this->scalar}\n"; $this->bla->Hello(); } } $container = new Wart(array(), array( 'createArgs' => array( '\Foo\Bar\Baz' => ['world'], '\Foo\Bar\Bla' => ['you'], '\Foo\Bar\Yadda' => function (array $createArgs, $className, \Wart $cnt) { // $createArgs contains the constructor parameters Wart has already figured out (i.e. all with class type hints) // Must return an array with all constructor args if ($buildArgs && $buildArgs[0] instanceof \Foo\Bar\Baz) use ($container) { # Wart found return [$buildArgs[0], "!", $cnt['\Foo\Bar\Baz']]; } throw new \Exception("Oh no!"); } ) )); $container->autoRegister('\Foo\Bar\Baz'); # does not return anything and does NOT create an object instance just yet $container['\Foo\Bar\Baz']->hello(); # prints "Hello world\n" $container['\Foo\Bar\Bla']->hello(); # prints "Hello you\n" $container['\Foo\Bar\Yadda']->hello(); # prints "Hello !\nHello you\n"
You can also set (replace!) the constructor parameters later on with setCreateArgs
<?php $container = new Wart; $container->setCreateArgs(array( '\Foo\Bar\Baz' => ['world'] ));
Limitations
Constructor parameter signature order
Mind that Wart
supports only auto determines constructor args which are type hinted classes.
The following Wart
tries to resolve and inject:
<?php class Foo { public function __construct(Bar $bar) {} }
The following Wart
cannot does not inject, unless you use the setCreateArgs
method or the createArgs
argument (see above).
<?php class Foo { public function __construct($bar) {} }
Now if the constructor parameter signature order is "adverse", Wart
cannot resolve it either. The following will not (automatically) work:
<?php class Bla { public function __construct($param, Baz $baz) # << Baz $baz is on second position, Wart gives up on first as it's not typehinted to a class { } }
Circular dependencies
Wart
features a simplistic circular dependency recognition. However it's limited in it's capabilities (especially in the context of constructor parameter order, see above)
The following will be recognized by Wart
(and a RuntimeException
is thrown):
<?php class Foo { public function __construct(Bar $bar) {} } class Bar { public function __construct(Baz $baz) {} } class Baz { public function __construct(Foo $foo) {} }
Anything else: no guarantees (patches welcome, unless they greatly increase the complexity).