diff options
author | David Négrier <d.negrier@thecodingmachine.com> | 2016-12-19 17:00:29 +0100 |
---|---|---|
committer | David Négrier <d.negrier@thecodingmachine.com> | 2016-12-19 17:00:29 +0100 |
commit | 36d0c089f4b8ab611a2bdda99d3ea59206a93621 (patch) | |
tree | 7bdd0362b08fad6384a246b1122447626aea32cb | |
parent | a6869ddaff9703c39f51111e929a0e9ae8572a78 (diff) | |
download | fig-standards-36d0c089f4b8ab611a2bdda99d3ea59206a93621.zip fig-standards-36d0c089f4b8ab611a2bdda99d3ea59206a93621.tar.gz fig-standards-36d0c089f4b8ab611a2bdda99d3ea59206a93621.tar.bz2 |
Removing the delegate lookup feature from PSR-11
-rw-r--r-- | proposed/container-meta.md | 224 | ||||
-rw-r--r-- | proposed/container.md | 40 | ||||
-rw-r--r-- | proposed/images/interoperating_containers.png | bin | 35971 -> 0 bytes | |||
-rw-r--r-- | proposed/images/priority.png | bin | 22949 -> 0 bytes | |||
-rw-r--r-- | proposed/images/side_by_side_containers.png | bin | 22519 -> 0 bytes |
5 files changed, 10 insertions, 254 deletions
diff --git a/proposed/container-meta.md b/proposed/container-meta.md index b0e99ac..eb41f0e 100644 --- a/proposed/container-meta.md +++ b/proposed/container-meta.md @@ -32,11 +32,6 @@ By standardizing the way entries are fetched from a container, frameworks and libraries using the Container PSR could work with any compatible container. That would allow end users to choose their own container based on their own preferences. -Also, some frameworks rely on very specific features offered only by their -own container. For these use cases, the Container PSR offers to implement the -"delegate lookup" feature that allows one container to fetch entries into -another container, therefore allowing 2 containers (or more) to run side-by-side. - ## 3. Scope ### 3.1. Goals @@ -303,206 +298,7 @@ public function get($identifier) { With this rule in place, a user of a container can safely know that a `NotFoundExceptionInterface` means the identifier he provided to the `get` method is missing, and not that some dependency is missing. -## 8. Delegate lookup feature - -### 8.1. Purpose of the delegate lookup feature - -The `ContainerInterface` is also enough if we want to have several containers side-by-side in the same -application. For instance, this is what the [CompositeContainer](https://github.com/jeremeamia/acclimate-container/blob/master/src/CompositeContainer.php) -class of [Acclimate](https://github.com/jeremeamia/acclimate-container) is designed for: - - - -However, an instance in container 1 cannot reference an instance in container 2. - -It would be better if an instance of container 1 could reference an instance in container 2, -and the opposite should be true. - - - -In the sample above, entry 1 in container 1 is referencing entry 3 in container 2. - -### 8.2. Chosen Approach - -Containers implementing this feature can perform dependency lookups in other containers. - -A container implementing this feature: - -- must implement the `ContainerInterface` -- must provide a way to register a *delegate container* (using a constructor parameter, or a setter, or any -possible way). The *delegate container* must implement the `ContainerInterface`. - -When a *delegate container* is configured on a container: - -- Calls to the `get` method should only return an entry if the entry is part of the container. -If the entry is not part of the container, an exception should be thrown (as required in the `ContainerInterface`). -- Calls to the `has` method should only return *true* if the entry is part of the container. -If the entry is not part of the container, *false* should be returned. - - Finally, the important part: if the entry we are fetching has dependencies, -**instead** of performing the dependency lookup in the container, the lookup is performed on the *delegate container*. - -Important! By default, the lookup should be performed on the delegate container **only**, not on the container itself. - -It is however allowed for containers to provide exception cases for special entries, and a way to lookup into -the same container (or another container) instead of the delegate container. - -### 8.3. Typical usage - -The *delegate container* will usually be a composite container. A composite container is a container that -contains several other containers. When performing a lookup on a composite container, the inner containers are -queried until one container returns an entry. -An inner container implementing the *delegate lookup feature* will return entries it contains, but if these -entries have dependencies, the dependencies lookup calls will be performed on the composite container, giving -a chance to all containers to answer. - -Interestingly enough, the order in which containers are added in the composite container matters. Indeed, -the first containers to be added in the composite container can "override" the entries of containers with -lower priority. - - - -In the example above, "container 2" contains a controller "myController" and the controller is referencing an -"entityManager" entry. "Container 1" contains also an entry named "entityManager". -Without the *delegate lookup* feature, when requesting the "myController" instance to container 2, it would take -in charge the instantiation of both entries. - -However, using the *delegate lookup* feature, here is what happens when we ask the composite container for the -"myController" instance: - -- The composite container asks container 1 if it contains the "myController" instance. The answer is no. -- The composite container asks container 2 if it contains the "myController" instance. The answer is yes. -- The composite container performs a `get` call on container 2 for the "myController" instance. -- Container 2 sees that "myController" has a dependency on "entityManager". -- Container 2 delegates the lookup of "entityManager" to the composite container. -- The composite container asks container 1 if it contains the "entityManager" instance. The answer is yes. -- The composite container performs a `get` call on container 1 for the "entityManager" instance. - -In the end, we get a controller instantiated by container 2 that references an *entityManager* instantiated -by container 1. - -### 8.4. Alternative: the fallback strategy - -The first proposed approach we tried was to perform all the lookups in the "local" container, -and if a lookup fails in the container, to use the delegate container. In this scenario, the -delegate container is used in "fallback" mode. - -This strategy has been described in @moufmouf [blog post (see solution 1)](http://mouf-php.com/container-interop-whats-next). -It was also discussed [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-33570697) and -[here](https://github.com/container-interop/container-interop/pull/20#issuecomment-56599631). - -Problems with this strategy: - -- Heavy problem regarding infinite loops -- Unable to overload a container entry with the delegate container entry - -### 8.5. Alternative: force implementing an interface - -A proposal was made on *container-interop* to develop a `ParentAwareContainerInterface` interface. -It was proposed here: https://github.com/container-interop/container-interop/pull/8 - -The interface would have had the behaviour of the delegate lookup feature but would have forced the addition of -a `setParentContainter` method: - -~~~php -interface ParentAwareContainerInterface extends ReadableContainerInterface { - /** - * Sets the parent container associated to that container. This container will call - * the parent container to fetch dependencies. - * - * @param ContainerInterface $container - */ - public function setParentContainer(ContainerInterface $container); -} -~~~ - -The interface idea was first questioned by @Ocramius [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-51721777). -@Ocramius expressed the idea that an interface should not contain setters, otherwise, it is forcing implementation -details on the class implementing the interface. -Then @mnapoli made a proposal for a "convention" [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-51841079), -this idea was further discussed until all participants in the discussion agreed to remove the interface idea -and replace it with a "standard" feature. - -**Pros:** - -If we had had an interface, we could have delegated the registration of the delegate/composite container to the -delegate/composite container itself. -For instance: - -~~~php -$containerA = new ContainerA(); -$containerB = new ContainerB(); - -$compositeContainer = new CompositeContainer([$containerA, $containerB]); - -// The call to 'setParentContainer' is delegated to the CompositeContainer -// It is not the responsibility of the user anymore. -class CompositeContainer { - ... - - public function __construct($containers) { - foreach ($containers as $container) { - if ($container instanceof ParentAwareContainerInterface) { - $container->setParentContainer($this); - } - } - ... - } -} - -~~~ - -**Cons:** - -Cons have been extensively discussed [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-51721777). -Basically, forcing a setter into an interface is a bad idea. Setters are similar to constructor arguments, -and it's a bad idea to standardize a constructor: how the delegate container is configured into a container is an -implementation detail. This outweighs the benefits of the interface. - -### 8.6 Alternative: no exception case for delegate lookups - -Originally, the proposed wording for delegate lookup calls was: - -> Important! The lookup MUST be performed on the delegate container **only**, not on the container itself. - -This was later replaced by: - -> Important! By default, the lookup SHOULD be performed on the delegate container **only**, not on the container itself. -> -> It is however allowed for containers to provide exception cases for special entries, and a way to lookup -> into the same container (or another container) instead of the delegate container. - -Exception cases have been allowed to avoid breaking dependencies with some services that must be provided -by the container (on @njasm proposal). This was proposed here: https://github.com/container-interop/container-interop/pull/20#issuecomment-56597235 - -### 8.7. Alternative: having one of the containers act as the composite container - -In real-life scenarios, we usually have a big framework (Symfony 2, Zend Framework 2, etc...) and we want to -add another DI container to this container. Most of the time, the "big" framework will be responsible for -creating the controller's instances, using it's own DI container. Until the Container PSR is fully adopted, -the "big" framework will not be aware of the existence of a composite container that it should use instead -of its own container. - -For this real-life use cases, @mnapoli and @moufmouf proposed to extend the "big" framework's DI container -to make it act as a composite container. - -This has been discussed [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-40367194) -and [here](http://mouf-php.com/container-interop-whats-next#solution4). - -This was implemented in Symfony 2 using: - -- [interop.symfony.di](https://github.com/thecodingmachine/interop.symfony.di/tree/v0.1.0) -- [framework interop](https://github.com/mnapoli/framework-interop/) - -This was implemented in Silex using: - -- [interop.silex.di](https://github.com/thecodingmachine/interop.silex.di) - -Having a container act as the composite container is not part of the delegate lookup standard because it is -simply a temporary design pattern used to make existing frameworks that do not support yet the Container PSR -play nice with other DI containers. - - -9. Implementations +8. Implementations ------------------ The following projects already implement the `container-interop` version of the interface and @@ -521,13 +317,6 @@ therefore would be willing to switch to a Container PSR as soon as it is availab - [PimpleInterop](https://github.com/moufmouf/pimple-interop) - [XStatic](https://github.com/jeremeamia/xstatic) -### Projects implementing the *delegate lookup* feature - -- [Aura.DI](https://github.com/auraphp/Aura.Di) -- [Mouf](http://mouf-php.com) -- [PHP-DI](http://php-di.org) -- [PimpleInterop](https://github.com/moufmouf/pimple-interop) - ### Middlewares implementing `ContainerInterface` - [Alias-Container](https://github.com/thecodingmachine/alias-container): add @@ -546,19 +335,19 @@ therefore would be willing to switch to a Container PSR as soon as it is availab micro-framework for writing APIs - [Invoker](https://github.com/mnapoli/Invoker): a generic and extensible callable invoker. -10. People +9. People --------- -### 10.1 Editors +### 9.1 Editors * [Matthieu Napoli](https://github.com/mnapoli) * [David Négrier](https://github.com/moufmouf) -### 10.2 Sponsors +### 9.2 Sponsors * [Matthew Weier O'Phinney](https://github.com/weierophinney) (Coordinator) * [Korvin Szanto](https://github.com/KorvinSzanto) -### 10.3 Contributors +### 9.3 Contributors Are listed here all people that contributed in the discussions or votes (on container-interop), by alphabetical order: @@ -577,7 +366,7 @@ Are listed here all people that contributed in the discussions or votes (on cont - [Stephan Hochdörfer](https://github.com/shochdoerfer) - [Taylor Otwell](https://github.com/taylorotwell) -11. Relevant links +10. Relevant links ------------------ - [Discussion about the container PSR and the service locator](https://groups.google.com/forum/#!topic/php-fig/pyTXRvLGpsw) @@ -589,4 +378,3 @@ Are listed here all people that contributed in the discussions or votes (on cont - <a name="link_method_and_parameters_details"></a>[Discussion about the method names and parameters](https://github.com/container-interop/container-interop/issues/6) - <a name="link_base_exception_usefulness"></a>[Discussion about the usefulness of the base exception](https://groups.google.com/forum/#!topic/php-fig/_vdn5nLuPBI) - <a name="link_not_found_behaviour"></a>[Discussion about the `NotFoundExceptionInterface` structure](https://github.com/container-interop/container-interop/issues/37) -- [Original article exposing the delegate lookup idea along many others](http://mouf-php.com/container-interop-whats-next) diff --git a/proposed/container.md b/proposed/container.md index fedb301..529adaa 100644 --- a/proposed/container.md +++ b/proposed/container.md @@ -59,38 +59,6 @@ which is a pattern that is generally discouraged. Please refer to section 4 of the META document for more details. -### 1.4 Additional feature: Delegate lookup - -This section describes an additional feature that MAY be added to a container. Containers are not -required to implement the *delegate lookup* to respect the `ContainerInterface`. - -The goal of the *delegate lookup* feature is to allow several containers to share entries. -Containers implementing this feature can perform dependency lookups in other containers. - -Containers implementing this feature will offer a greater lever of interoperability -with other containers. Implementation of this feature is therefore RECOMMENDED. - -A container implementing this feature: - -- MUST implement the `ContainerInterface` -- MUST provide a way to register a delegate container (using a constructor parameter, or a setter, - or any possible way). The delegate container MUST implement the `ContainerInterface`. - -When a container is configured to use a delegate container for dependencies: - -- Calls to the `get` method should only return an entry if the entry is part of the container. - If the entry is not part of the container, an exception should be thrown - (as requested by the `ContainerInterface`). -- Calls to the `has` method should only return `true` if the entry is part of the container. - If the entry is not part of the container, `false` should be returned. -- If the fetched entry has dependencies, **instead** of performing - the dependency lookup in the container, the lookup is performed on the *delegate container*. - -Important! By default, the lookup SHOULD be performed on the delegate container **only**, not on the container itself. - -It is however allowed for containers to provide exception cases for special entries, and a way to lookup -into the same container (or another container) instead of the delegate container. - 2. Package ---------- @@ -101,11 +69,11 @@ Packages providing a psr container implementation should declare that they provi Projects requiring an implementation should require `psr/container-implementation` `1.0.0`. -2. Interfaces +3. Interfaces ------------- <a name="container-interface"></a> -### 2.1. `Psr\Container\ContainerInterface` +### 3.1. `Psr\Container\ContainerInterface` ~~~php <?php @@ -147,7 +115,7 @@ interface ContainerInterface ~~~ <a name="container-exception"></a> -### 2.2. `Psr\Container\Exception\ContainerExceptionInterface` +### 3.2. `Psr\Container\Exception\ContainerExceptionInterface` ~~~php <?php @@ -162,7 +130,7 @@ interface ContainerExceptionInterface ~~~ <a name="not-found-exception"></a> -### 2.3. `Psr\Container\Exception\NotFoundExceptionInterface` +### 3.3. `Psr\Container\Exception\NotFoundExceptionInterface` ~~~php <?php diff --git a/proposed/images/interoperating_containers.png b/proposed/images/interoperating_containers.png Binary files differdeleted file mode 100644 index 9c672e1..0000000 --- a/proposed/images/interoperating_containers.png +++ /dev/null diff --git a/proposed/images/priority.png b/proposed/images/priority.png Binary files differdeleted file mode 100644 index 5760dc7..0000000 --- a/proposed/images/priority.png +++ /dev/null diff --git a/proposed/images/side_by_side_containers.png b/proposed/images/side_by_side_containers.png Binary files differdeleted file mode 100644 index 24ca03c..0000000 --- a/proposed/images/side_by_side_containers.png +++ /dev/null |