Hi David, Thank you for taking the time to consider my proposal. While many points expressed by you are true, however, this is now how I see things.
The `ParentAwareContainerInterface` is a formal way of saying "this container can have a parent". Nothing more, nothing less. The "delegate feature" is simply a *pattern* that is possible as a result of that formalization - because now containers can form a hierarchy, which is impossible (reliably) without this formalized bond. In simpler words, lookup delegation is not a formal albeit optional feature of the *standard*, but rather something that is possible to implement via the standard. All we're doing is giving implementations the possibility of a reliable hierarchy. If they want to implement lookup delegation, they can now do it. >From this point of view, the consumer of the `ParentAwareContainerInterface` can be any consumer wishing to access the hierarchy, not only a child container. For example, an implementation may want to print or log a string that represents a "lookup path" by giving each container a code. Thus, this interface is useful to any consumer that needs to be hierarchy-aware. Up to now, there is no concept of hierarchy in the standard, and the use of the interface would be to introduce that concept. Also, using a "definition resolution" mechanism demonstrated in my implementation, one could have as a parent something that is not necessarily a composite container - but maybe simply another container to delegate lookup to. Thus, the concept of "parent" is given an even more precise definition as simply "something that takes precedence in service definition resolution". Kinda similar to how DOM events work. With regard to the expense of parent lookup. Typical use, as I described in the project's readme, would involve invocation of the `get()` method on the topmost container, which would be the only container that the consuming application needs to be aware of. According to the composite container spec, the composite container does not perform service lookup in the regular sense of this word, but matches the service ID with child containers. Like this, caching (again, typical use) remains on the level of the matching container (the one that matches, i.e. contains the service definition). As a result, parent lookup will only be performed once per service - not because the parent is cached, but because the service referencing the parent is cached. Like this, containers remain independent of their parent, which is a great level of flexibility that may be beneficial in some scenarios. In other words, child containers may be potentially re-attached to other parents, without breaking the hierarchy mechanism. On the other hand, a DI implementation that allows simple values as service definition (e.g. Pimple) can have the correct values retrieved after the parent is switched. It could also be possible to implement caching on the level of the root container, further increasing speed. I guess, the point I am trying to make is that *everything still remains optional, but is now possible in the scope of the standard specification*. I think this is a part of what constitutes a good standard, and therefore I conclude that the `ParentAwareContainerInterface` is still necessary. Also, again in light of the above explanation, I do not believe that "root parent" resolution *should* necessarily be done before the child container is created. In my proposed approach, it remains an implementation detail that *can* be done this way. Looking forward to your further comments, as well as those of other participants! On Monday, October 10, 2016 at 12:48:56 PM UTC+2, David Négrier wrote: > > > <https://lh3.googleusercontent.com/-MJQw2yspEUE/V_tt0Bg3xPI/AAAAAAAAB8s/Z6txSatzpM83T_v0AqUvcQXvgitUuzS1ACLcB/s1600/container_explanation.png> > > > > <https://lh3.googleusercontent.com/-MJQw2yspEUE/V_tt0Bg3xPI/AAAAAAAAB8s/Z6txSatzpM83T_v0AqUvcQXvgitUuzS1ACLcB/s1600/container_explanation.png> > > Hey, > > Ok I spent the week-end trying to think about the pros and cons of this > proposal. > > @XedinUnknown, I'm not sure I understood 100% of your proposal so I'll try > to rephrase it. If I'm wrong, let me know. > > I understand you are trying to improve the "delegate lookup feature". Your > goals are: > > - to make it "explicit" that a container is implementing the "delegate > lookup feature" > - to make it possible to nest containers at an unlimited level (to be able > to nest a composite container in another composite container...) > > To do so, you propose to add a new interface named > ParentAwareContainerInterface > <https://github.com/XedinUnknown/di/blob/master/src/ParentAwareContainerInterface.php>. > > This interface is exposing a single method "getParentContainer()" that > returns the parent container if any (i.e. the composite container > containing this container). > When resolving a dependency, the container goes up the chain of parent > containers > <https://github.com/XedinUnknown/di/blob/master/src/AbstractParentAwareContainer.php#L39-L55> > > until it reaches the root container. It uses the root container to look up > any dependency (just like in the current delegate lookup feature). > > Here are a few thoughts about this idea: > > First: who is consuming the ParentAwareContainerInterface > <https://github.com/XedinUnknown/di/blob/master/src/ParentAwareContainerInterface.php>? > > This interface is consumed by "child" containers. If a container is a leaf > in the container tree (so if it is not a composite container), then there > is no need for it to implement the ParentAwareContainerInterface > <https://github.com/XedinUnknown/di/blob/master/src/ParentAwareContainerInterface.php>. > > The interface is trivial to implement and is a good declaration of intent > (your container states it supports delegate lookup feature) but it is none > the less useless. This interface is only useful for composite containers > (so that they can also be bundled into parent composite containers). > > Second, each container now needs to find the root container by going up > the container tree. In your sample, you do this while resolving a service > <https://github.com/XedinUnknown/di/blob/master/src/AbstractParentAwareContainer.php#L64>. > > This is a bit of a problem performance-wise because this will slow service > resolving (and this is a major no no for many implementors). Of course, > there is a simple way around that. Finding the root container could be done > only once, possibly in the constructor. This assumes that the parent > container is passed to the child container constructor (or at build time). > This also assumes that the parent container will never change in the life > of a container (this is a safe assumption). Looking at @XedingUnknown code, > this means that stuff like containers with mutable parents > <https://github.com/XedinUnknown/di/blob/master/src/ContainerWithMutableParent.php> > > should be forbidden and only containers with immutable parents > <https://github.com/XedinUnknown/di/blob/master/src/ContainerWithImmutableParent.php> > > should be allowed. > > If we assume that the "parent" container is always passed to containers in > their constructor, it means that containers MUST be constructed in the > order of the tree (from top to bottom). > > > > <https://lh3.googleusercontent.com/-MJQw2yspEUE/V_tt0Bg3xPI/AAAAAAAAB8s/Z6txSatzpM83T_v0AqUvcQXvgitUuzS1ACLcB/s1600/container_explanation.png> > > > <https://lh3.googleusercontent.com/-MJQw2yspEUE/V_tt0Bg3xPI/AAAAAAAAB8s/Z6txSatzpM83T_v0AqUvcQXvgitUuzS1ACLcB/s1600/container_explanation.png> > > I made a picture so it would be more clear. If the "root container" exists > before "Composite A" and if "Composite A" exists before "Container 1", then > when "container 1" is created, instead of passing an instance of composite > A, it should directly be passed an instance of the root container. That > way, "container 1" does not have to go up the tree to find the root > container. This makes the proposed "ParentAwareContainerInterface" useless, > because finding the root container can be and should be done *before* the > container is created. > > @XedingUnknown, I understand your concerns that the "delegate lookup > feature" of PSR-11 is not backed by a solid interface. After careful > consideration, I'm not sure your proposal of adding a getter really solves > any issues (because we already can nest several containers). However, you > are making clear that we never spoke about the way containers should be > created (and who should come first between the parent and the child > container). After thinking about your proposal, what is now clear to me is > that the parent should be created before the children (and maybe we should > stress that out in the META document). > > If I was to add another interface, it would more likely be a "container > factory" (a la zend-expressive) that can create a container while passing > the parent container in parameter: > > interface ContainerFactoryInterface { > // A composite container could use an array of > ContainerFactoryInterface to build containers, passing them the very root > container. > public function createContainer(ContainerInterface $rootContainer); > } > > @mnapoli, @mweierophinney, any thoughts about this? Do you think we need > to consider this or am I overtinking things? > > I think we also need to discuss more here the "delegate lookup feature". > It is an optional feature, not backed by an interface and this is > unprecedented in other PSRs (correct me if I'm wrong but I don't think > other PSRs have similar optional features). To the rest of the members > here, do you think we should do something special regarding this? > Espceially, how should an implementing container advertise that it is > supporting PSR-11 with/without delegate lookup feature? > > Best regards, > David. > > > Le vendredi 7 octobre 2016 18:58:51 UTC+2, Xedin Unknown a écrit : >> >> Hi all, >> >> The delegate lookup feature of Container Interop didn't get as much >> attention as I feel it deserves. Specifically, it is lacking formalization >> in PHP - an interface. I started this conversation , but was instructed >> that the mailing list is the better way to go. >> It seems that many would agree with me in that it would be great to have >> the standard backed by an interface. There was talk of an interface >> <https://github.com/container-interop/container-interop/pull/8>, but the >> idea was shot down due to forcing the implementation to declare a setter. I >> completely agree that forcing a setter is a bad idea. >> *But why not a getter?* >> >> * <https://github.com/XedinUnknown/di>* >> *XedinUnknown/di <https://github.com/XedinUnknown/di>* is an example of >> an implementation that would achieve lookup delegation while depending on >> one method of one interface. The rest is implementation details. >> In short, the container that wishes to delegate must pass its parent (or, >> in my implementation, the "root" parent), if set, to the service definition >> callable. If the callable is a composite container, it will forward the >> call to the first child container that contains the definition. Please find >> a more expanded description in the repo's Readme. >> >> Looking forward to your comments, questions, or suggestions. >> > -- You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group. To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscr...@googlegroups.com. To post to this group, send email to php-fig@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/3b0fdce0-507a-40d3-8b68-606f405ee6b8%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.