8000 [YAML] Added support for object-maps by polyfractal · Pull Request #10114 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[YAML] Added support for object-maps #10114

8000 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

Conversation

polyfractal
Copy link
Contributor

Previously, the parser treated maps ({}) the same as sets ([]). Both were returned as a PHP associative array. Since these are distinct entities, this can cause considerably problems if you treat the two types differently, especially when YAML is being serialized into another format such as JSON.

This PR enables empty-map support via a third optional parameter on the Parse method. It defaults to false, which means that this commit does not break backwards compatibility.

If the user enables object-map support, maps are represented by a stdClass() object. Sets remain as PHP arrays. This is compatible with other serialization methods, such as json_encode where empty objects are properly encoded to {}.

The tests are a little bulky, since assertSame() is too strict (e.g. two empty objects are not identical, since they are discrete objects), but assertEquals() is too loose (e.g. loses type-checking on the rest of the values). I've implemented a recursive assert that uses the stricter assertSame() on non-objects, and a slightly looser combo of asserts for objects.

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | NA
| License       | MIT
| Doc PR        | NA

@stof
Copy link
Member
stof commented Jan 23, 2014

Returning an object for an empty map is totally unusable for calling code as it must now distinguish the case of an empty or non-empty map (which is still an array).
Matchng the behavior of json_decode by using an object for *all maps when using this new flag would be far better from a usability PoV

Previously, the parser treated maps ( {} ) the same as sets ( [] ).
Both were returned as PHP associative arrays.  Since
these are distinct entities, this can cause considerably problems for
the users, especially when YAML is being serialized into another
format such as JSON.

This commit allows the user to enable object-map support via a third
parameter on the Parse method.  It defaults to `false`, which means
that this commit does not break backwards compatibility.

If the user enables object-map support, maps are represented
by stdClass() objects.  Sets remain as arrays.
@polyfractal
Copy link
Contributor Author

Reconfigured the code to return objects for all maps, instead of array + empty objects as before. Tests have been updated to reflect the changes depending on which flag you use.

Also updated the title of the PR and the description to match the new functionality. Added PR form/table too.

@polyfractal
Copy link
Contributor Author

Updated PR to comply with coding standards.

@Taluu
Copy link
Contributor
Taluu commented Feb 21, 2014

I think rather than checking each time if you're using an object or not, you could work with an array, and then at the end test your objectMap value, and if it is true, cast the array as an object. You'll have an stdClass, and it should be far more maintainable.

@polyfractal
Copy link
Contributor Author

Yeah, that makes sense. Updated the code to check only on return. Tests seem to pass...but there was a random failure in Symfony/Component/Stopwatch/Tests/StopwatchEventTest which is marking it failed.

There is also a small coding standard fix that I'll push if this newest iteration of code looks good. Thanks for taking a look!

@@ -312,17 +314,19 @@ private static function parseSequence($sequence, &$i = 0)
throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this extra lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing! I didn't think about it because Fabbot didn't yell at me :)

$this->assertFail();
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh, yep. Lemme look through the whole PR and see if I've done this anywhere else :)

@polyfractal
Copy link
Contributor Author

@Taluu Haha, no worries, @cordoval already yelled at me for the same issue. Should be fixed in most recent commit :)

However, there isn't currently a newline between the if{} and the return...is that something fabbot is going to whinge about?

Edit: yep :(

@@ -295,7 +296,8 @@ private static function parseSequence($sequence, &$i = 0)
if (!$isQuoted && false !== strpos($value, ': ')) {
// embedded mapping?
try {
$value = self::parseMapping('{'.$value.'}');
$j = 0;
$value = self::parseMapping('{'.$value.'}', $j, $objectForMap);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The j variable is a bit useless here, why don't you use 0 as argument?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, it is required. :(

parseMapping() requires the second parameter to be passed by reference:

private static function parseMapping($mapping, &$i = 0, $objectForMap = false)

PHP disallows passing constants by reference because the method may mutate the value (and indeed it does). So you must create a temporary variable and pass that instead. PHP doesn't mind if you omit the parameter because of the default on the function, but if you specify arguments that come after the referenced parameter, you must supply one.

I could do the variable assignment inline, but it's effectively the same thing:

$value = self::parseMapping('{'.$value.'}', $j = 0, $objectForMap);

Open to alternatives, but I did it this way because alternative approaches (removing the reference) would require fairly drastic restructuring of how the parsing works for what is ultimately just a little semantic blemish :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, missed that. Sad it has to be done this way :(

@polyfractal
Copy link
Contributor Author

Anything else that needs to be done? I have a whole pile of code that would love to start differentiating between objects and arrays :)

nicolas-grekas added a commit to nicolas-grekas/symfony that referenced this pull request Mar 27, 2014
nicolas-grekas added a commit to nicolas-grekas/symfony that referenced this pull request Mar 27, 2014
@nicolas-grekas
Copy link
Member

Hello @polyfractal ,
I just made some cleanups on your code, in an other PR as it was easier.
See also inline comments at nicolas-grekas@bede5ce

@fabpot
Copy link
Member
fabpot commented Mar 27, 2014

Closing in favor of #10552

@fabpot fabpot closed this Mar 27, 2014
nicolas-grekas added a commit to nicolas-grekas/symfony that referenced this pull request Mar 27, 2014
nicolas-grekas added a commit to nicolas-grekas/symfony that referenced this pull request Mar 27, 2014
fabpot added a commit that referenced this pull request Jun 4, 2014
…olas-grekas)

This PR was merged into the 2.5-dev branch.

Discussion
----------

 [YAML] Added support for object-maps

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | NA
| License       | MIT
| Doc PR        | NA

Proposal for #10114

Commits
-------

0cee604 [Yaml] Cleanups for object maps
e2d5468 [Yaml] Added support for object maps
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants
0