Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[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

Closed
ro0NL wants to merge5 commits intosymfony:masterfromro0NL:di/dump-privates
Closed

[DI] Randomize private services#19683

ro0NL wants to merge5 commits intosymfony:masterfromro0NL:di/dump-privates

Conversation

@ro0NL
Copy link
Contributor

@ro0NLro0NL commentedAug 20, 2016
edited
Loading

QA
Branch?"master"
Bug fix?yes
New feature?yes
BC breaks?no
Deprecations?no
Tests pass?not yet
Fixed tickets#19680
LicenseMIT
Doc PRreference to the documentation PR, if any

Alternative approach compared to#19682

Thanks to@wouterj for explaining this approach.

Theory of operation;

  • compiler pass
    • build a map ofprivate id =>random id
    • remap private definitions to its new id
    • update references and aliases
    • inject id map into container builder (for BC)
  • container
    • id's found in the (injected) map are forwarded to the new id + deprecation notice
  • todo
    • add tests
    • fix tests due randomization
    • dump the container with orignal id's in generated docs, etc. for convenience.

The deprecation now only happens after compilation(!). This can be seen a design choice, i guess.

@ro0NLro0NL changed the titleDi/dump privates[DI] Fix sharing privatesAug 20, 2016

$code .="\n\$this->services = array();\n";
$code .=$this->addMethodMap();
$code .=$this->addPrivateServices();
Copy link
ContributorAuthor

@ro0NLro0NLAug 20, 2016
edited
Loading

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
Copy link
Member

This is basically a big copy/paste from the originalget() function, right? I don't like that too much (it gets out of sync very quick and requires more work when some code is changed inget()/resolveService()).

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
Copy link
ContributorAuthor

ro0NL commentedAug 20, 2016
edited
Loading

This is about separating (concerns), not copy-paste. Basically this makesget final, have a look at the diff.

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 cleanupget.. unless you make a real good guess ;-) which should still, eh trigger.

@ro0NL
Copy link
ContributorAuthor

Im not even sure we need random id's, if it's bulletproof already.

@sstok
Copy link
Contributor

sstok commentedAug 20, 2016
edited
Loading

Im not even sure we need random id's, if it's bulletproof already.

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
Copy link
Member

Even then, if you have a "random id" you need to be able to get it internally, without deprecations. That would only cleanup get.. unless you make a real good guess ;-) which should still, eh trigger.

A compiler would generate random IDs for private services and fix the service definitions that depend on them. No need to change anything in theContainer.

@ro0NL
Copy link
ContributorAuthor

ro0NL commentedAug 20, 2016
edited
Loading

@wouterj Fair enough 👍

I just dont understand how that reflects dumping..;

  • generate random id
  • update references
  • a private service needs to be injected by some id
    • are we gonna bypass the container to get the object?

@sstok i think it's boosted (we bypassget many times now).. but im not sure. Not familiar yet with blackfire.io.. could you collab?

@wouterj
Copy link
Member

I just dont understand how that reflects dumping..;

  1. Compiler finds private service
  2. Generates random ID
  3. Updates all references to the old ID with the generated one
  4. Container is dumped, using the random ID for the service, just like normal.

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
Copy link
Contributor

You could start by randomizing them already, and use those. But keep an alias array with private services, pointing to the actual id 👍

wouterj reacted with thumbs up emoji

@ro0NL
Copy link
ContributorAuthor

ro0NL commentedAug 20, 2016
edited
Loading

Based on the current design;

  • php dumper generates calls to (private) services usingget(). How will that not trigger/throw,
    unless we alterget to allow for privates? Again; are we gonna bypass the container getter?
  • having a list of private id's (randomized or not) is useful
  • randomizing id's is a next step

@wouterj
Copy link
Member

wouterj commentedAug 20, 2016
edited
Loading

php dumper generates calls to (private) services using get(). How will that not trigger/throw? Again are gonna bypass the container methods?

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}
sstok reacted with thumbs up emoji

@ro0NL
Copy link
ContributorAuthor

ro0NL commentedAug 20, 2016
edited
Loading

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;get is a api method that does normalization and such. Using it internal seems overhead.

@wouterj
Copy link
Member

Still; get is a user method that does normalization and such. Using it internal seems overhead.

The internalget() method skips almost all of the method. The first condition matches for new services and the method is simply called. (Seehttps://github.com/symfony/dependency-injection/blob/master/Container.php#L258-L259 )

Leaving a minor leak whenever the user has a random id some way, some how.

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
Copy link
ContributorAuthor

ro0NL commentedAug 20, 2016
edited
Loading

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$id = $this->privates[$id]; you can access a private service (what we're gonna do internally right? :-)). Anyway, doesnt matter they're not exposed, and nobody makes that good guesses.

@ro0NLro0NL changed the title[DI] Fix sharing privates[WIP][DI] Fix sharing privatesAug 20, 2016
@sstok
Copy link
Contributor

sstok commentedAug 20, 2016
edited
Loading

The@trigger_error(..., E_USER_DEPRECATED); $id = $this->privates[$id]; is for BC only, in the future this resolving is simple removed, and as the original service-id is replaced with something random it will fail (saying the service doesn't exist).

@ro0NL
Copy link
ContributorAuthor

@sstok@wouterj ping ping :-)

This works out pretty nice so far...

@ogizanagi
Copy link
Contributor

ogizanagi commentedAug 20, 2016
edited
Loading

@ro0NL: Even if your work looks great,@wouterj 's approach has the benefits of keeping things simple and pragmatic to fix the related issue.
I don't know if it's a good idea both trying to fix the issue and introducing the private services id generation into the very same PR as a "bug fix". It won't be a bug fix anymore, but somehow mixing bug fix, new feature and BC for this new feature. I'd say it's too much :/

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
Copy link
ContributorAuthor

ro0NL commentedAug 20, 2016
edited
Loading

Im just playing around with randomizing now.. eventually i want to revert what i did toget. (The changes are not that dramatic).

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.

@ro0NLro0NL changed the title[WIP][DI] Fix sharing privates[WIP][DI] Randomize private servicesAug 20, 2016
@ro0NL
Copy link
ContributorAuthor

@fabpot as this was youridea more or less.. WDYT?

Tests are failing nicely so far;

@@ @@-        $instance->dep = $this->get('shared_private');+        $instance->dep = $this->get('2a21409629880ccd9259eda073b930c1');         return $instance;     }     /**-     * Gets the 'shared_private' service.+     * Gets the '2a21409629880ccd9259eda073b930c1' service.@@ @@      */-    protected function getSharedPrivateService()+    protected function get2a21409629880ccd9259eda073b930c1Service()     {-        return $this->services['shared_private'] = new \stdClass();+        return $this->services['2a21409629880ccd9259eda073b930c1'] = new \stdClass();     }

We have the map now inContainer.. so we can really be flexible (ie. only use the random id for code, not docs).

$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));
Copy link
Contributor

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
Copy link
Contributor

Status: Needs work

@ro0NL
Copy link
ContributorAuthor

ro0NL commentedAug 21, 2016
edited
Loading

@sstok would it make sense to mark a random definition (old private) as public after compiling? Currently we deprecatedhas etc. for all privates (random or not), but inget we must allow for it (if requested by the random id).

This doesnt make sense to me:has('random') // false vs.get('random') // object. Marking them public simplifies things :)

@ro0NLro0NL changed the title[WIP][DI] Randomize private services[DI] Randomize private servicesAug 21, 2016
@nicolas-grekas
Copy link
Member

We might require this kind of randomization on 4.0 when getting private service will be removed.
For now, I don't think it provides more external side effect than#19708.
If I'm not wrong, this could be closed in favor of#19708
WDYT?

@stof
Copy link
Member

Yeah, I don't think we need to do this in 3.x

@ro0NL
Copy link
ContributorAuthor

ro0NL commentedAug 22, 2016
edited
Loading

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

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

Copy link
ContributorAuthor

@ro0NLro0NLAug 23, 2016
edited
Loading

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 :)

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.

Copy link
ContributorAuthor

@ro0NLro0NLAug 24, 2016
edited
Loading

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 :)).

Copy link
Member

@nicolas-grekasnicolas-grekasAug 24, 2016
edited
Loading

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.

Copy link
ContributorAuthor

@ro0NLro0NLAug 24, 2016
edited
Loading

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 (thinkDebugPhpDumper)
  • Forget about randomizing, and compile different method names (thinkgetPrivate(.+)Service)
    • Nah.. this makes theContainer work with "privates" again 😕

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... :)

Copy link
ContributorAuthor

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).

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.

fabpot added a commit that referenced this pull requestSep 1, 2016
…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
Copy link
Member

So, followingthe discussion above, my stand on this is:

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.

This meansnot randomizing private services, even in 4.0.
Given that 4.0 is far away, I think we should close this PR, at least for now.
It's way too early to work on it and the issue will naturally arise when working on 3.4/4.0 when we'll work on cleaning deprecations.

xabbuh reacted with thumbs up emoji

@ro0NL
Copy link
ContributorAuthor

👍 eventually it comes down to track private id's yes/no. Like currently..

Personally i'd favor randomizing id's in thePhpDumper.. (privates are just normal services).

But it doesnt matter much i guess.

@ro0NLro0NL closed thisSep 7, 2016
@ro0NLro0NL deleted the di/dump-privates branchSeptember 24, 2016 13:46
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

7 participants

@ro0NL@wouterj@sstok@ogizanagi@nicolas-grekas@stof@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp