The Container implementation checks all passed values if they are of Instance (Yii2) or Reference (Yii 3) and resolves them by calling get()
of the container using the id stored in the reference object.
In Yii2 Instance has a member function called get which in turn calls container->get()
. Unfortunately the container implementation does not call $v->get($this)
, but $this->get($v->id)
. And in Yii 3 get()
in Reference is completely gone.
Why would I prefer the first over the latter despite it would finally do the same?
Sometimes it might be necessary to use “complex” values as parameters. The container can resolve a single object reference, but not an array of references. This requires the object to know about the container in order to finally resolve the passed references.
To solve this problem I propose a ResolveInterface:
interface ResolveInterface
{
/**
* @param Container $container
* @return mixed
public get ($container)
}
Reference should implement this interface and just do
return $container->get($this->id);
But using this interface other types of references could be implemented (even custom references):
class RefrenceArray implements ResolveInterface
{
/* ... */
public function get($container)
{
$result = [];
foreach ($this->arrayItems as $k => $v) {
$result[$k] = ($v instanceof ResolveInterface) ? $v->get($container) : $v;
}
return $result;
}
}
In the dependency declaration it just requires:
[
/* ... */
'thePropertyTakingAnArrayOfObjects' => RefrenceArray:of([
Refrerence::to('foo'),
Reference::to('bar')])
/* ... */
]
If the container implementation just checked on $dependency instanceof ResolveInterface
and called $dependency->get($this)
we would get a comfortable way to resolve anything.
IMO this is important because DI obviously becomes more important in Yii 3 and one of the goals is to separate the actual classes from the container. Thus, as much as possible needs to be done by the container.
Of course such problems could be worked around by not using a declaration of dependency, but closures to create the actual instance. But then we lose the elegance of configuration.
With such a interface we could do anything - even funny things like generating a random value:
RandValue implements ResolveInterface
{
public function get($container)
{
return mt_rand(999); /* We do not care about the container - we just need the value */
}
}
I know that this is a silly example, but it might show the flexibility the approach provides.