Skip to content

[PropertyInfo] Fix edge cases in ReflectionExtractor #20154

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

Merged
merged 1 commit into from
Oct 6, 2016

Conversation

nicolas-grekas
Copy link
Member

@nicolas-grekas nicolas-grekas commented Oct 4, 2016

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

This should make ReflectionExtractor a bit more robust.

ping @dunglas (don't miss the changed test case).

$phpType = Type::BUILTIN_TYPE_OBJECT;
$typeClass = $typeHint->name;
if ($phpType) {
$collectionValueType = new Type($phpType, $nullable, $typeClass);
Copy link
Member

Choose a reason for hiding this comment

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

the behavior for $nullable does not match the previous code, which was using a $collectionNullable variable. $nullable is weird the collection itself is nullable, not whether collection values are

Copy link
Member Author

@nicolas-grekas nicolas-grekas Oct 4, 2016

Choose a reason for hiding this comment

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

The $nullable behavior change is related to the same semantic mistake (no offense to anyone) fixed in #20152 (there are no two "allowsNull" & "isNullable" separate concepts).
$collectionNullable === $nullable && $arrayMutator, which is what the code does.
Or did you spot something else? Any demo case where you think the adjusted behavior is wrong?

@@ -69,7 +69,7 @@ public function typesProvider()
array('b', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy'))),
array('c', array(new Type(Type::BUILTIN_TYPE_BOOL))),
array('d', array(new Type(Type::BUILTIN_TYPE_BOOL))),
array('e', null),
array('e', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT)))),
Copy link
Member

Choose a reason for hiding this comment

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

Maybe am I missing something but the e virtual property is defined only by a adder and a remover. We know for sure that it's a collection, but we cannot know if it's an indexed array or any other type of collection.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, but why this line and this one then?

Copy link
Member

Choose a reason for hiding this comment

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

Technically, it's an iterable, but as it's a 7.1+ only feature, I don't think that it's ok to use it in Symfony for now.

Copy link
Member

Choose a reason for hiding this comment

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

After double checking, I've an explanation for this test. It is not related at all with the type of the property, but with the type of elements of its collection.

Some context: in the default setup of the standard edition, the ReflectionExtractor is registered with a higher priority than the PhpDocExtractor because it is faster; but it is also less precise.

The remover for the f property is type hinted with \DateTime. It's a reliable source of information. Regardless the type defined in the PHPDoc of the $e property, elements of the collections will be of type \DateTime (it's ensured at runtime because of the type hint).
The ReflectionExtractor is able to guess that f is a collection of \DateTime objects and return this type.

On the other hand, the adder of e isn't type hinted. The ReflectionExtractor cannot guess the type of elements of the collection. But the PhpDocExtractor may have a chance to guess it if the PHPDoc is defined for the e property. So ReflectionExtractor returns null in this case to give a chance to the PhpDocExtractor (or any other extractor registered with a lower property) to detect the type of elements.

This change is a (small) BC break, I think that the old behavior is preferable.

I'm not sure that my explanation is clear. Let me know if I need to add an example.

Copy link
Member Author

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

@dunglas understood, behavior fixed. Should be good now.
As a side note, we don't handle "iterable" yet. By looking at the RFC, iterable is the same as array|Traversable, which could mean no need for a new builtin type, and manage it as array|Traversable instead? (Just throwing the idea, that's for another PR)

if (!$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType()) {
return;
}
} elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $reflectionParameter, $info)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

By using the string representation of the parameter to get the type hint (on PHP5 only of course), we prevent autoloading of the corresponding class.

if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) {
$type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true);
} elseif ('void' === $phpTypeOrClass) {
$type = new Type(Type::BUILTIN_TYPE_NULL, $nullable);
Copy link
Member Author

Choose a reason for hiding this comment

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

missing "void" handling added here also

Copy link
Member

Choose a reason for hiding this comment

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

Can you add a test for this new one?

Copy link
Member Author

Choose a reason for hiding this comment

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

Test added

@dunglas
Copy link
Member

dunglas commented Oct 6, 2016

👍 (but the new test for void would be nice to have). Thank you very much!

@dunglas
Copy link
Member

dunglas commented Oct 6, 2016

... and one more bug fixed, thank you Nicolas.

@dunglas dunglas merged commit bffdfad into symfony:2.8 Oct 6, 2016
dunglas added a commit that referenced this pull request Oct 6, 2016
…las-grekas)

This PR was merged into the 2.8 branch.

Discussion
----------

[PropertyInfo] Fix edge cases in ReflectionExtractor

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

This should make ReflectionExtractor a bit more robust.

ping @dunglas (~~don't miss the changed test case~~).

Commits
-------

bffdfad [PropertyInfo] Fix edge cases in ReflectionExtractor
@nicolas-grekas nicolas-grekas deleted the propinfo-clean branch October 6, 2016 09:23
This was referenced Oct 27, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants