8000 [DI] Public, private and hidden services · Issue #27293 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DI] Public, private and hidden services #27293

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

Closed
javiereguiluz opened this issue May 17, 2018 · 11 comments
Closed

[DI] Public, private and hidden services #27293

javiereguiluz opened this issue May 17, 2018 · 11 comments
Labels
DependencyInjection Feature RFC RFC = Request For Comments (proposals about features that you want to be discussed)

Comments

@javiereguiluz
Copy link
Member
javiereguiluz commented May 17, 2018

Description
In the past, services were public or private (I'm ignoring "synthetic" services and other edge cases):

  • Public: these are the services that you can use in your app. Also, you can $this->get() them in controllers.
  • Private: don't use these services in your own code! These are "internal" services created by Symfony or third-party bundles. In modern Symfony versions you can't get them with $this->get() because they have random service IDs.

Also, private services don't appear on debug:container. It makes sense.

Problem
In recent Symfony versions we made all services private by default. In my opinion, the problem is that we don't really want to make services private. In fact, those services are used in your app, so their "nature" is to be public. We make them private so you can't do $this->get() to get them (and to unlock some performance improvements).

Proposal
What if we do this:

  • Remove all features to get services with $this->get() in controllers and commands and force to always inject services. This is a BC break, only possible in Symfony 5.
  • Restore the previous behavior: all services are public, unless you make them private for some reason. Private services don't appear on debug:container
  • Remove the concept of "hidden services", which are now "private services" again.
@javiereguiluz javiereguiluz added DependencyInjection Feature RFC RFC = Request For Comments (proposals about features that you want to be discussed) labels May 17, 2018
@linaori
Copy link
Contributor
linaori commented May 17, 2018

So if I understand the proposal correctly, using $container->get() would not be possible anymore?

@stof
Copy link
Member
stof commented May 17, 2018

Private services were never about internal services, even in 2.0.0. You were always able to inject them in your own services, in any way you want.
Private services were always about telling the container: "I won't ever get this service dynamically, so you know all places accessing it and can perform any optimization you want on it".

Also, private services don't appear on debug:container. It makes sense.

That's actually something done later in the Symfony history, and not at all the reason to introduce private services.

because they have random service IDs.

that's totally wrong. Their id is not randomized at all. They get excluded from the map of available services when dumping (and their instances are stored in a separate map internally, but using their actual id).

@stof
Copy link
Member
stof commented May 17, 2018

I think the issue is the naming of this concept. A private service is not restricted to a single bundle (there is no such concept, as they all share the same container). It is private to the container (only the container can get the instance to use it elsewhere, but your own code cannot). I think public was chosen because it describes that the services can be accessed through the container public API (note that the code has public: false, not private: true. Naming something a "private service" is a documentation thing).

What we could do is rename public to something better describing the fact that it is a service exposed to the PSR-11 service location container API

@linaori
Copy link
Contributor
linaori commented May 17, 2018

expose: true ?

@stof
Copy link
Member
stof commented May 17, 2018

and your own vision of "private services" still does not correspond to what @nicolas-grekas wants to build with hidden services, because the "hidden" state is tied to the identifier, not to the service definition (so works also for identifiers being used by aliases, keeps working if you override the service definition for an identifier, etc...).
I don't think trying to change the concept of "private services" to something different is the right move (and it would be a documentation nightmare)

@javiereguiluz
Copy link
Member Author

@stof regarding the random service IDs, I was referring to PRs like #19683, and comments like this: #19117 (comment)

In any case, I still think that "public" (you can use this) and "private" (don't use these services; they are for internal purposes) would be easier to understand that "public" (don't use this; all private by default), "private" (but not really private/internal, you can use them almost as public) and "hidden" (which are hidden in some places, but you can still use them, like a public/private service).

@stof
Copy link
Member
stof commented May 17, 2018

@javiereguiluz there is a difference between don't use this and don't use it elsewhere than in service definitions.
We don't have any concept of internal service that others cannot use (because as soon as you create a service definition, it belongs to the ContainerBuilder, not to a bundle. The DI component does not have a bundle concept).

@nicolas-grekas
Copy link
Member
nicolas-grekas commented May 17, 2018

We don't have any concept of internal service that others cannot use

and this is actually a requirement of the DI design pattern: being able to rewire things as you want. There is no such things as "private wiring", bundle or not.

The original description uses the same words "private/public" for very different and unrelated concepts.
Also, random ids do not exist at all, we never merged anything like that.
And there is a big misunderstanding about hidden services, #27284 should be just closed.

The already started story is to split services in 3 groups:

  • hidden services are the services whose ids are just noise to any user land use case: their name is usually randomly generated based on a hash. e.g. generated service locators, anonymous services;
  • important services, which are the entry points of the features provided by bundles, to be used by users mainly in their DI configuration. These services are currently not separated from the next group and that's what Drastically improved debug:autowiring + new autowiring info system #26142 first, [RFC] Introduce "semantics": a way to make service ids meaningful by binding them to types+descriptions #27207 latest target to improve;
  • all the other services generated/declared by bundles/di-extensions. These are the services that are needed to make the important services work, that have a clean name but are not intended for direct wiring by users (yet, they CAN rewire them, that's all the power of DI, so this should still be possible for advanced use cases.)

All in all, this issue is a duplicate.

@javiereguiluz
Copy link
Member Author

I'm closing this issue as Nicolas asked. I also closed the other issue too (#27284) although it had 67 upvotes and zero downvotes 😢

@Wirone
Copy link
Contributor
Wirone commented May 18, 2018

hidden services are the services whose ids are just noise to any user land use case: their name is usually randomly generated based on a hash. e.g. generated service locators, anonymous services;

@nicolas-grekas Still, they can be hidden by configuration, not by convention. If bundles want to hide internal services to not make noise for developer, why should they use special dot notation instead of configuring them with hidden: true?

@nicolas-grekas
Copy link
Member
nicolas-grekas commented May 18, 2018

Because IMHO it makes no sense to significantly increase the complexity of the code base to handle this concern while the current solution fits very simply and naturally the existing code. And also as I said in the linked issue, conceptually this doesn't belong to dependency injection configuration.

BUT let it be clear: if anyone disagrees enough to make a PR and prove its points then fine. I'm "just" the implementer of the current system and it deserved some explanations, which are not only in my head now, so that this can be challenged more easily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DependencyInjection Feature RFC RFC = Request For Comments (proposals about features that you want to be discussed)
Projects
None yet
Development

No branches or pull requests

5 participants
0