Shared chain call
pattisahusiwa opened this issue · comments
I've rules like this.
{
"Factory": {
"shared": true
},
"$object": {
"instanceOf": "Factory",
"call": [
[
"getObject",
[],
"Dice::CHAIN_CALL"
]
]
}
}
Calling $dice->create('$object')
or $dice->create('Factory')
multiple times will return the same object as expected.
The Factory
also needs to access the same instance as defined in $object
. However, in the code below $objectA
and $objectB
point to different instances.
$objectA = $dice->create('$object');
$factory = $dice->create('Factory');
$objectB = $factory->getObject();
Can this feature be added to Dice? So, both $objectA
and $objectB
point to the same instance.
Since $object
is considered a different instance of Factory
then it will not be the same. If they were shared then you would never be able to define a different version of the object, for example if you had PDO
and $otherPDO
.
Honestly, I've rules like this
{
"$objectA": {
"instanceOf": "Factory",
"call": [
[
"getObjectA",
[],
"Dice::CHAIN_CALL"
]
]
},
"$objectB": {
"instanceOf": "Factory",
"call": [
[
"getObjectB",
[],
"Dice::CHAIN_CALL"
]
]
}
}
Both rules require the same instance, so the rule below is added. However, current implementation doesn't allow this use case.
"Factory": {
"shared": true
}
If they were shared then you would never be able to define a different version of the object, for example if you had
PDO
and$otherPDO
.
We can use something like this
{
"$otherPDO": {
"instanceOf": "PDO",
"shared": false
}
}
We can use something like this
I just remembered that there is the inherit: false
syntax to prevent the issue I was describing.
I think the main issue here is that $objectA
and $objectB
are not actually instances of Factory
but instead something created by it. In my experience the config {"Dice::INSTANCE" : ["Factory", "getObjectA"]}
would return the same objectA
instance every time it is retrieved. This issue is that the instanceOf
and call
method of getting objectA
is different in the way it processes it.
Suppose I've
$factory = new Factory();
$classA = new ClassA($factory->getObjectA());
$classB = new ClassB($factory->getObjectB());
$classC = new ClassC($classA, $classB);
I need to create $classC
directly without create $factory
, $classA
, and $classB
manually.
$classC = $dice->create('ClassC');
Can dice be used for this use case?
I don't think this is currently possible with json rules, but you can do it with closures:
$dice->addRules([
'classC' => [
'substitutions' => [
'ClassA' => [\Dice\Dice::INSTANCE => function() use ($factory) {
return $factory->getObjectA();
}],
'ClassB' => [\Dice\Dice::INSTANCE => function() use ($factory) {
return $factory->getObjectB();
}]
]
]
]);
Factory and DIC are different approaches to the same problem. With DIC you generally don't need factories as the same can usually be achieved in the container and all the factory is really doing is providing functionality already provided by the container:
{
"ClassA": {
//rules for objectA instantiation (currently in your factory)
},
"ClassB": {
//rules for objectB instantiation (currently in your factory)
}
}
class ClassC {
public function __construct(ClassA $objectA, ClassB $objectB) {
}
}
$dice->create('ClassC');
We can use something like this
I just remembered that there is the
inherit: false
syntax to prevent the issue I was describing.I think the main issue here is that
$objectA
and$objectB
are not actually instances ofFactory
but instead something created by it. In my experience the config{"Dice::INSTANCE" : ["Factory", "getObjectA"]}
would return the sameobjectA
instance every time it is retrieved. This issue is that theinstanceOf
andcall
method of gettingobjectA
is different in the way it processes it.
The main issue is objectA
is initialized inside factory and is passed into objectB
by the factory itself. So, when objectA
is changed, objectB
has the state too.
This use case is similar to Aura/Router
. Map
, Matcher
, and Generator
can be retrieved from RouterContainer
. However, Matcher
and Generator
point to the same Map
that reside inside the container.
@pattisahusiwa If you know the class you are passing it into then it is possible currently.
@TRPB Using Dice::INSTANCE
will allow passing the same instance here because Dice::INSTANCE
calls create
then calls the methods on it when the instanceOf
and call
method does not create the same factory first.
Example code that I believe should work here (because I have had this same issue before)
{
"Factory": {
"shared": true
},
"ClassC" : {
"constructParams" : [
{"Dice::INSTANCE" : ["Factory", "getClassA"]},
{"Dice::INSTANCE" : ["Factory", "getClassB"]},
]
}
}