Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[VarExporter] add Instantiator::instantiate() to create+populate objects without calling their constructor nor any other methods#28417
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
b157f1d to702fb4dCompareUh oh!
There was an error while loading.Please reload this page.
| useSymfony\Component\VarExporter\Internal\Registry; | ||
| /** | ||
| * A utility class to create objects without calling their constructor. |
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.
Most likely a good idea to keep this@internal until proven to be stable for usage within the component
nicolas-grekasSep 10, 2018 • 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.
The proposed method borrows from the existing infrastructure in the component: if there are any issues withInstantiator::instantiate(), it's also an issue forVarExporter::export(). It would make no sense to mark this method as internal, and not the other.
And if we mark the other internal, then the component would have zero public interfaces. It wouldn't make sense :)
| * // creates an empty instance of Foo | ||
| * Instantiator::instantiate([Foo::class => []]); | ||
| * | ||
| * // creates a Foo instance and sets one of its public, protected or private properties |
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.
Thepublic/private/protected case should likely be always distinguished, because of inheritance and possible property overrides.
| * Instantiator::instantiate([Foo::class => ['propertyName' => $propertyValue]]); | ||
| * | ||
| * // creates a Foo instance and sets a private property defined on its parent Bar class | ||
| * Instantiator::instantiate([ |
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.
This syntax is very confusing: the object type should be the firststring parameter. What's the reasoning behind putting the first type inside the array?
| * Instances of ArrayObject, ArrayIterator and SplObjectHash can be created | ||
| * by using the special "\0" property name to define their internal value: | ||
| * | ||
| * // creates an SplObjectHash where $info1 is attached to $obj1, etc. |
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.
Strongly suggest keeping anything coming from php core or extensions out of the scope of the component, as well as its documentation: there's an infinity of wrongness in classed that are not defined in PHP userland, and we really should rather tell users to not rely on them.
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.
Same as above: this is already dealt with forVarExporter::export(), so any issue found there should be spotted and fixed. There are already tests for these btw (which doesn't mean it's yet bulletproof of course.)
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
javiereguiluz commentedSep 10, 2018 • 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 for the detailed description! Looking at the end-user API, I have two comments/questions:
// BeforeInstantiator::instantiate([ Foo::class => [], Bar::class => ['propertyName' =>$propertyValue],]);// AfterInstantiator::instantiate(Foo::class, []);Instantiator::instantiate(Bar::class, ['propertyName' =>$propertyValue]);
// BeforeInstantiator::instantiate([SplObjectStorage::class => ["\0" => [$obj1,$info1,$obj2,$info2]]]);Instantiator::instantiate([ArrayObject::class => ["\0" =>$inputArray]]);// AfterInstantiator::instantiate(SplObjectStorage::class, [$obj1 =>$info1,$obj2 =>$info2]);Instantiator::instantiate(ArrayObject::class,$inputArray); |
702fb4d to3465299CompareUh oh!
There was an error while loading.Please reload this page.
3465299 to6eacb76Comparenicolas-grekas commentedSep 10, 2018 • 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.
@Ocramius@javiereguiluz thanks for the review+comments, I addressed some inline, let's address the remaining ones: I added a 2nd commit to change the signature to
It's not actually: e.g. you can also add dynamic properties to ArrayObject instances, that arenot stored in the internal array structure. The This doesn't mean we cannot do what you propose@javiereguiluz, but we still need a way to set dynamic properties when needed. Actually, there is a trivial way that works already: using an So, let's say we want to create something like that using instantiate: $a =newArrayObject($input);$a->foo =123; The current code allows doing so using: Instantiator::instantiate(ArrayObject::class, ['foo' =>123,"\0" => [$input]]); And wecould make it do the same using: Instantiator::instantiate(ArrayObject::class, [$input], ['stdClass' => ['foo' =>123]]); Please advise. |
javiereguiluz commentedSep 10, 2018
Thanks for the detailed explanation. I hadn't thought about this use case: $a =newArrayObject($input);$a->foo =123; I thought this utility was only for instantiating ... but that code instantiates and then initializes, so it's doing two different things :) What if we use this signature? Then, this example would look as: Instantiator::instantiate(ArrayObject::class, [$input], ['foo' =>123]) But most of the times you'd simply use something like this: Instantiator::instantiate(ArrayObject::class, [$input]) |
nicolas-grekas commentedSep 10, 2018
@javiereguiluz wouldn't make sense: the specific property of instantiators is tonot call the constructor nor any other methods... |
javiereguiluz commentedSep 10, 2018
I just followed your last example: why pass |
javiereguiluz commentedSep 10, 2018
After talking with Nico on Slack about this ... it's clear to me that I don't fully understand this 😅 So let's forget about my previous examples and proposals. Sorry! |
6eacb76 tob2308d7Compareb2308d7 to127a2bdComparenicolas-grekas commentedSep 10, 2018
Good news: shaking the code always helps to spot new edge cases. |
5b16b53 toc18f056CompareThis PR was merged into the 4.2-dev branch.Discussion----------[VarExporter] fix more edge cases| Q | A| ------------- | ---| Branch? | master| Bug fix? | yes| New feature? | no| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | -| License | MIT| Doc PR | -As found while preparing#28417Commits-------443bd11 [VarExporter] fix more edge cases
c18f056 to77376e4Comparenicolas-grekas commentedSep 11, 2018
Fixes split in PR#28437. This PR is now rebased on top of it. |
| class InstantiatorTestextends TestCase | ||
| { | ||
| use VarDumperTestTrait; |
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 im missing it.. but this can be removed right?
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.
good catch, removed thanks
…cts without calling their constructor nor any other methods
77376e4 tod9bade0Comparefabpot commentedSep 26, 2018
@nicolas-grekas We needs good docs on that one (and the whole component). Can you create a PR for that in the docs repo? I think it won't take too much of your time as you're the best to write something smart about this :) |
fabpot commentedSep 26, 2018
Thank you@nicolas-grekas. |
…e+populate objects without calling their constructor nor any other methods (nicolas-grekas)This PR was merged into the 4.2-dev branch.Discussion----------[VarExporter] add Instantiator::instantiate() to create+populate objects without calling their constructor nor any other methods| Q | A| ------------- | ---| Branch? | master| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | -| License | MIT| Doc PR | -A blend of features also provided byhttps://github.com/doctrine/instantiator andhttps://github.com/Ocramius/GeneratedHydrator in one simple method. Because it's just a few more lines on top of the existing code infrastructure in the component :)For example, from the docblock:```php// creates an empty instance of FooInstantiator::instantiate(Foo::class);// creates a Foo instance and sets one of its public, protected or private propertiesInstantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]);// creates a Foo instance and sets a private property defined on its parent Bar classInstantiator::instantiate(Foo::class, [], [ Bar::class => ['privateBarProperty' => $propertyValue],]);```Instances of ArrayObject, ArrayIterator and SplObjectHash can be createdby using the special `"\0"` property name to define their internal value:```php// creates an SplObjectHash where $info1 is attached to $obj1, etc.Instantiator::instantiate(SplObjectStorage::class, ["\0" => [$obj1, $info1, $obj2, $info2...]]);// creates an ArrayObject populated with $inputArrayInstantiator::instantiate(ArrayObject::class, ["\0" => [$inputArray, $optionalFlag]]);```Misses some tests for now, but reuses the existing code infrastructure used to "unserialize" objects.Commits-------d9bade0 [VarExporter] add Instantiator::instantiate() to create+populate objects without calling their constructor nor any other methods
Uh oh!
There was an error while loading.Please reload this page.
A blend of features also provided byhttps://github.com/doctrine/instantiator andhttps://github.com/Ocramius/GeneratedHydrator in one simple method. Because it's just a few more lines on top of the existing code infrastructure in the component :)
For example, from the docblock:
Instances of ArrayObject, ArrayIterator and SplObjectHash can be created
by using the special
"\0"property name to define their internal value:Misses some tests for now, but reuses the existing code infrastructure used to "unserialize" objects.