Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[DI] Randomize private services#19683
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
| $code .="\n\$this->services = array();\n"; | ||
| $code .=$this->addMethodMap(); | ||
| $code .=$this->addPrivateServices(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Needed to trigger deprecations inget for a compiled container when dumped.
wouterj commentedAug 20, 2016
This is basically a big copy/paste from the original Also, please note that in Symfony 4, private services will be implemented by using a randomly generated service ID. So implementing a complete new API for private services isn't needed. |
ro0NL commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
This is about separating (concerns), not copy-paste. Basically this makes About 4.x changes.. that is eventually still future talk. I compare against the current codebase. Even then, if you have a "random id" you need to be able to get it internally, without deprecations. That would only cleanup |
ro0NL commentedAug 20, 2016
Im not even sure we need random id's, if it's bulletproof already. |
sstok commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Using random id's makes it possible to use same logic, it be like using a normal id except you don't know the id. Is it possible to benchmark these changes with Blackfire.io? I'm worried performance could be degraded. |
wouterj commentedAug 20, 2016
A compiler would generate random IDs for private services and fix the service definitions that depend on them. No need to change anything in the |
ro0NL commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@wouterj Fair enough 👍 I just dont understand how that reflects dumping..;
@sstok i think it's boosted (we bypass |
wouterj commentedAug 20, 2016
As said by@sstok, the only difference between a private and a public service will be that you don't know the ID of the private one (as it's automatically generated). |
sstok commentedAug 20, 2016
You could start by randomizing them already, and use those. But keep an alias array with private services, pointing to the actual id 👍 |
ro0NL commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Based on the current design;
|
wouterj commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
If requested service is the randomized ID, it's an internal call and thus should not trigger deprecations. If it uses the original service ID, it's a call from outside world and the deprecation should be triggered (and randomized service returned). E.g: publicfunctionget($id, ...){if (isset($this->privates[$id])) { @trigger_error(...,E_USER_DEPRECATED);$id =$this->privates[$id]; }// ... behave like normal, $id is either a public service or the randomized ID} |
ro0NL commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Ok, that clarifies. Leaving a minor leak whenever the user has a random id some way, some how. We could live with that, i guess 👍 i personally favor the separation by design though. Still; |
wouterj commentedAug 20, 2016
The internal
We don't check for random ID (what's random?), we check if the ID exists in the array that contains generated IDs by the compiler. |
ro0NL commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Thanks@wouterj this was really clarifying, and probably makes a separate method obsolete. What about if we do it right now? I really dont think we should bridge it with workarounds (no offense). edit: about the leak; whenever you have |
sstok commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
The |
ro0NL commentedAug 20, 2016
ogizanagi commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@ro0NL: Even if your work looks great,@wouterj 's approach has the benefits of keeping things simple and pragmatic to fix the related issue. But that's only my opinion, a core member is more legitimate to hint you on this. Just saying you should probably don't work too hard on this right now ;) |
ro0NL commentedAug 20, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Im just playing around with randomizing now.. eventually i want to revert what i did to However, the tests are updated to the right behavior. That was was an effort, yes. I understand@wouterj 's approach and motivation, im only proposing a structural solution to consider as we can currently still target master. |
ro0NL commentedAug 20, 2016
@fabpot as this was youridea more or less.. WDYT? Tests are failing nicely so far; We have the map now in |
| $this->idMap = array(); | ||
| foreach ($container->getDefinitions() as $id => $definition) { | ||
| if (!$definition->isPublic()) { | ||
| $this->idMap[$id] = $this->randomizer ? (string) call_user_func($this->randomizer, $id) : md5(uniqid($id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
uniqid should not be used here, it's anything but unique and actually causes collisions very easily.
Seehttps://github.com/symfony/symfony/blob/master/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php#L291 for how it's done there.
sstok commentedAug 21, 2016
Status: Needs work |
ro0NL commentedAug 21, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@sstok would it make sense to mark a random definition (old private) as public after compiling? Currently we deprecated This doesnt make sense to me: |
nicolas-grekas commentedAug 22, 2016
stof commentedAug 22, 2016
Yeah, I don't think we need to do this in 3.x |
ro0NL commentedAug 22, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I dont mind :) i just dont like how we work with privates right now. And ido think this is the cleanest solution eventually, as the container does not have to care about privates. Currently leading to all sorts of quirkiness, as you might have noticed. But yes, the pass can be added on top of#19708 in 4.x. From the component pov i would prefer this though (understanding the scope is wider, however wedo advertise with standalone components ;-)). |
| * | ||
| * @author Roland Franssen <franssen.roland@gmail.com> | ||
| */ | ||
| class RandomizePrivateServiceIdentifiers implements CompilerPassInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
IMO, randomization shouldn't be handled by a compiler pass, but by the PhpDumper directly. Otherwise it won't be applied without the compiler, and many apps won't have it enabled when migrating to 4.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I considered this. But eventually chose to separate it into a compiler pass (yes; making it an optional feature). Without compiling you have anormal container.
Thing is i dont really like the concept of coupliing privates with a container. The container shouldnt care about privates (it's just a normal service from that perspective). Hence$this->privates could be totally unneeded...
No need to bypassget or checking private definitions inPhpDumper. We work with the container :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
What you call anormal container doesn't have private services. The container shouldn't care about private services, right, but the PhpDumpershould (and already does). So I still think that the PhpDumper should do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We disagree :) i think we have compiler passes for that (optional) or otherwiseContainer::compile (by design).
A dumper (eg.PhpDumper) dumps the given container as is. Like others do, YAML, XML etc. I dont know whyPhpDumer would randomize your services, whereasXmlDumper doesnt.
Currently it only deals with privates tohack the dumped container (ie. output), saying; here's a list of privates for you to validate business logic (which it shouldnt care about :)).
nicolas-grekasAug 24, 2016 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Because it makes no sense to randomize withXmlDumper and in fact would be wrong: it would rename services for no reason and make dumps harder and not accurate.
What matters is having dumpers deal with private services, whichXmlDumper does by adding thepublic="false" attribute, andPhpDumper doing some randomization. That! would make sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Reconsidered :)
Because it makes no sense to randomize with XmlDumper and in fact would be wrong: it would rename services for no reason and make dumps harder and not accurate.
My first thought was, yeah this totally counts for aPhpDumper as well. Which in some ways is still true, but i guess you're right. Randomizing could bethe way a php dumper deals with privates by design (whereas xml addspublic="false" 👍 ).
Do we need to consider DX here?
- Make it depend on some debug flag?
- Have 2 implementations (think
DebugPhpDumper) Forget about randomizing, and compile different method names (thinkgetPrivate(.+)Service)- Nah.. this makes the
Containerwork with "privates" again 😕
- Nah.. this makes the
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Not sure how DX is involved here. So maybe but I don't what it'd mean :)
Forget about randomizing, and compile different method names
maybe :) the goal is to have private services be hidden from the outside, no interference with the public interface.
How it's done is an implementation detail We should chose the simplest one... :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We should chose the simplest one
True.
DX, in the sense that you may not want to have random id's in the output, or at least customize/mock it in some way (thinksetRandomizer).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Then maybe the simplest and most DX friendly is to make private services leak a bit by reserving their id, throwing an exception whenever one uses or fetches an id that collides with a private service.
…ces internally (nicolas-grekas)This PR was merged into the 3.2-dev branch.Discussion----------[DI] Dont use Container::get() when fetching private services internally| Q | A| ------------- | ---| Branch? | master| Bug fix? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets |#19683,#19682,#19680| License | MITAs spotted by@wouterj, we forgot to remove the deprecation notice when doing internal calls to get private services.Yet, we don't need to get through this `get()` method, because we can already resolve many things at compile time for private services. This will provide another small performance optim, and fix the issue.Commits-------a9c79fb [DI] Dont use Container::get() when fetching private services internally
nicolas-grekas commentedSep 6, 2016
So, followingthe discussion above, my stand on this is:
This meansnot randomizing private services, even in 4.0. |
ro0NL commentedSep 7, 2016
👍 eventually it comes down to track private id's yes/no. Like currently.. Personally i'd favor randomizing id's in the But it doesnt matter much i guess. |
Uh oh!
There was an error while loading.Please reload this page.
Alternative approach compared to#19682
Thanks to@wouterj for explaining this approach.
Theory of operation;
private id=>random idThe deprecation now only happens after compilation(!). This can be seen a design choice, i guess.