Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Poll: needed features #9

Open
moufmouf opened this issue Dec 26, 2015 · 7 comments
Open

Poll: needed features #9

moufmouf opened this issue Dec 26, 2015 · 7 comments

Comments

@moufmouf
Copy link

Now that we listed all possible features we could think of, let's rank these features!

Here is my personal take on it. I'm opening this issue so we can discuss on it. Maybe we can summarize this in the META or in a GIST later. If you have a better idea, let me know.

Feature Rating Comment
Ability to create a container entry using the new keyword. ++
Ability to call methods (setters or otherwise) on a container entry ++
Ability to set public properties of a container entry. + Although setting public properties directly is not the best practice, I feel it is important that containers we write can adapt to such things.
Ability to set private and protected properties of a container entry. -- I feel this should be highly discouraged. I don't care if some containers out there allow it, but forcing all containers implementing this standard to be able to bypass protected/private modifiers feels plainly wrong
Ability to create a container entry using a static factory method. +
Ability to create a container entry using a factory method from a container service. ++
Ability to create a container entry using a closure /
Ability to compile all container entries into a single container for maximum performance. +
Ability to alias a container entry to another. ++
Ability to modify an entry defined outside of the "module" before it is returned by the container. ++
Ability to create container entries for scalar values. ++
Ability to create container entries from constants (from the define keyword or the const keyword) +
Ability to create container entries that are numerically indexed arrays. Values of the array can be any valid container entry (i.e. objects, scalars, another array...) ++
Ability to create container entries that are associative arrays (maps). Values of the array can be any valid container entry (i.e. objects, scalars, another array...) ++
Ability for a package to extend those arrays (add elements to the arrays). ++
Ability for a package to manage priority in those arrays +
Ability to locally declare "anonymous"/"private" services in a package. +
Ability to provide a default service that should be used when binding an interface. - I don't think a package should be allowed to provide a "default" implementation of an interface, as there could be conflicts between packages providing default implementations for the same interface. This should be something decided by the application, not the packages.
Ability to declare "lazy" services (services that are wrapped into proxy objects and instanciated only when needed) / Very specific feature. Can be achieved by using factories. I'm not sure it deserves a "special treatment"
Ability to have several services for the same class or interface (for instance, several services implementing a LoggerInterface). ++
Ability to declare if the service should be instantiated once and reused (singleton) or if the service should be instantiated every time it is injected or fetched from the container. - I believe two successive calls from a container on a given ID should ALWAYS return the same service. If people need factories, they can use the container to retrieve a factory, and then use the factory to get new instances of the object they want. I feel we should not melt containers and factories. They are different beasts.
Ability to have "optional" references +
Ability to have fall-back aliases/services: a alias/service is only declared by a package if no other package has provided that service so far. /
Ability to have static tools analyzing the bindings (for instance, having Packagist analyze the bindings to search for some services...) + I'm definitely very keen on this feature (would rate it +++), but I understand this can be a problem for "closure-based" solutions, so I only rated it "+"
Ability to have static tools help us edit the binding. For instance, a dedicated UI that can be used to create services and drag'n'drop services together (like Mouf does) + I'm definitely very very keen on this feature (would rate it ++++), but I understand this can be a problem for anything that is not a configuration file based solution, so I only rated it "+"
Ability to perform simple computations on values before injecting them in a container entry +

Everybody wanting to give a rating is welcome!

@webmozart
Copy link

I think "Ability to compile all container entries into a single container for maximum performance." should be ++, since this is absolutely needed to be compatible with compiled containers.

@mnapoli
Copy link
Member

mnapoli commented Dec 30, 2015

since this is absolutely needed to be compatible with compiled containers.

I don't see how it's absolutely needed? The only benefit I see is for performances, but compiled containers can work fine with "service providers" (for example of non-compilable definitions): the compiled container can call factories that will handle creating the objects.

Example:

class TwigServiceProvider implements ServiceProvider
{
    public function getExposedServices()
    {
        return [
            'twig' => 'createTwig',
        ];
    }

    public function createTwig(ContainerInterface $c)
    {
        return Twig_Environment($c->get(...), ...);
    }
}

That means the compiled container will call createTwig() whenever it needs Twig.

@webmozart
Copy link

You're right, good point!

@mnapoli
Copy link
Member

mnapoli commented Dec 30, 2015

Here is my take then. Not much different from you @moufmouf.

Feature Rating Comment
Ability to create a container entry using the new keyword. ++
Ability to call methods (setters or otherwise) on a container entry ++
Ability to set public properties of a container entry. +
Ability to set private and protected properties of a container entry. -- Shouldn't be supported in a standard supporting minimal features for modules
Ability to create a container entry using a static factory method. +
Ability to create a container entry using a factory method from a container service. ++
Ability to create a container entry using a closure +
Ability to compile all container entries into a single container for maximum performance. +
Ability to alias a container entry to another. ++
Ability to modify an entry defined outside of the "module" before it is returned by the container. ++
Ability to create container entries for scalar values. ++
Ability to create container entries from constants (from the define keyword or the const keyword) +
Ability to create container entries that are numerically indexed arrays. Values of the array can be any valid container entry (i.e. objects, scalars, another array...) ++
Ability to create container entries that are associative arrays (maps). Values of the array can be any valid container entry (i.e. objects, scalars, another array...) ++
Ability for a package to extend those arrays (add elements to the arrays). ++
Ability for a package to manage priority in those arrays - To me it's feature creep, I don't see a valid use case for the standard yet (use cases I've seen should be ordered by users themselves, not automagically)
Ability to locally declare "anonymous"/"private" services in a package. / Can be solved indirectly by using a factory I think?
Ability to provide a default service that should be used when binding an interface. -
Ability to declare "lazy" services (services that are wrapped into proxy objects and instanciated only when needed) -- Shouldn't be in a simple standard IMO, too complex and only useful in weird cases
Ability to have several services for the same class or interface (for instance, several services implementing a LoggerInterface). -- I don't think I understand this one, arrays are already described above
Ability to declare if the service should be instantiated once and reused (singleton) or if the service should be instantiated every time it is injected or fetched from the container. -- I've never seen a valid use case for not singleton: it would make the container a factory
Ability to have "optional" references / I'm don't understand this one
Ability to have fall-back aliases/services: a alias/service is only declared by a package if no other package has provided that service so far. /
Ability to have static tools analyzing the bindings (for instance, having Packagist analyze the bindings to search for some services...) /
Ability to have static tools help us edit the binding. For instance, a dedicated UI that can be used to create services and drag'n'drop services together (like Mouf does) - IMO this has nothing to do with a minimal standard for modules, specific container features can still be used by users, just not by module authors
Ability to perform simple computations on values before injecting them in a container entry +

@moufmouf
Copy link
Author

moufmouf commented Jan 4, 2016

I realized that there is maybe something missing in the poll. Maybe we should ask whether the standard we design should focus on simplicity (KISS principle) or performance in case we have to do a trade-off.

Because as I see things, we are going to have to do some choices. Using the example from @mnapoli :

class TwigServiceProvider implements ServiceProvider
{
    public function getExposedServices()
    {
        return [
            'twig' => 'createTwig',
        ];
    }

    public function createTwig(ContainerInterface $c)
    {
        return Twig_Environment($c->get(...), ...);
    }
}

A compiled container would have to call the createTwig function to get a twig environment. This is one extra function call (and potentially an additional provider instantiation) compared to a "native" implementation using definitions.

Please note I don't have any preference regarding this issue. My mind is definitely not made up in this topic.

Another "feature" maybe missing is the ability to directly debug the code (as you can put a breakpoint in a service provider), but it is really harder in a YML/XML configuration file.

@mnapoli
Copy link
Member

mnapoli commented Jan 4, 2016

This is one extra function call (and potentially an additional provider instantiation) compared to a "native" implementation using definitions.

Agreed, but is that really significant? I don't have enough expertise in writing frameworks to answer honestly… We also have to consider that it only applies for entries defined in modules: do they represent 20%, 50% or 80% of all definitions in an application?

Another "feature" maybe missing is the ability to directly debug the code (as you can put a breakpoint in a service provider), but it is really harder in a YML/XML configuration file.

+1 this is nice to have.

@moufmouf
Copy link
Author

@abachmann, I assume you are talking about ContainerInterface (aka PSR-11).

This issue refers to service providers (e.g. another PSR that is not yet in draft).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants