From bffdfad41ec2c447883c5a0f7a0fe311438de138 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 4 Oct 2016 15:27:03 +0200 Subject: [PATCH] [PropertyInfo] Fix edge cases in ReflectionExtractor --- .../Extractor/ReflectionExtractor.php | 98 +++++++------------ .../Extractors/ReflectionExtractorTest.php | 1 + .../Tests/Fixtures/Php71Dummy.php | 4 + 3 files changed, 40 insertions(+), 63 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 1d3d3a2083..7643d8971e 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -44,6 +44,13 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp */ public static $arrayMutatorPrefixes = array('add', 'remove'); + private $supportsParameterType; + + public function __construct() + { + $this->supportsParameterType = method_exists('ReflectionParameter', 'getType'); + } + /** * {@inheritdoc} */ @@ -134,68 +141,33 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp $reflectionParameters = $reflectionMethod->getParameters(); $reflectionParameter = $reflectionParameters[0]; - $arrayMutator = in_array($prefix, self::$arrayMutatorPrefixes); - - if (method_exists($reflectionParameter, 'getType') && $reflectionType = $reflectionParameter->getType()) { - $fromReflectionType = $this->extractFromReflectionType($reflectionType); - - if (!$arrayMutator) { - return array($fromReflectionType); + if ($this->supportsParameterType) { + if (!$reflectionType = $reflectionParameter->getType()) { + return; } + $type = $this->extractFromReflectionType($reflectionType); - $phpType = Type::BUILTIN_TYPE_ARRAY; - $collectionKeyType = new Type(Type::BUILTIN_TYPE_INT); - $collectionValueType = $fromReflectionType; - } - - if ($reflectionParameter->isArray()) { - $phpType = Type::BUILTIN_TYPE_ARRAY; - $collection = true; - } - - if ($arrayMutator) { - $collection = true; - $nullable = false; - $collectionNullable = $reflectionParameter->allowsNull(); - } else { - $nullable = $reflectionParameter->allowsNull(); - $collectionNullable = false; - } - - if (!isset($collection)) { - $collection = false; - } - - if (method_exists($reflectionParameter, 'isCallable') && $reflectionParameter->isCallable()) { - $phpType = Type::BUILTIN_TYPE_CALLABLE; - } - - if ($typeHint = $reflectionParameter->getClass()) { - if ($collection) { - $phpType = Type::BUILTIN_TYPE_ARRAY; - $collectionKeyType = new Type(Type::BUILTIN_TYPE_INT); - $collectionValueType = new Type(Type::BUILTIN_TYPE_OBJECT, $collectionNullable, $typeHint->name); + // HHVM reports variadics with "array" but not builtin type hints + if (!$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType()) { + return; + } + } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $reflectionParameter, $info)) { + if (Type::BUILTIN_TYPE_ARRAY === $info[1]) { + $type = new Type(Type::BUILTIN_TYPE_ARRAY, $reflectionParameter->allowsNull(), null, true); + } elseif (Type::BUILTIN_TYPE_CALLABLE === $info[1]) { + $type = new Type(Type::BUILTIN_TYPE_CALLABLE, $reflectionParameter->allowsNull()); } else { - $phpType = Type::BUILTIN_TYPE_OBJECT; - $typeClass = $typeHint->name; + $type = new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $info[1]); } - } - - // Nothing useful extracted - if (!isset($phpType)) { + } else { return; } - return array( - new Type( - $phpType, - $nullable, - isset($typeClass) ? $typeClass : null, - $collection, - isset($collectionKeyType) ? $collectionKeyType : null, - isset($collectionValueType) ? $collectionValueType : null - ), - ); + if (in_array($prefix, self::$arrayMutatorPrefixes)) { + $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type); + } + + return array($type); } /** @@ -213,7 +185,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp return; } - if (method_exists($reflectionMethod, 'getReturnType') && $reflectionType = $reflectionMethod->getReturnType()) { + if ($this->supportsParameterType && $reflectionType = $reflectionMethod->getReturnType()) { return array($this->extractFromReflectionType($reflectionType)); } @@ -231,15 +203,15 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp */ private function extractFromReflectionType(\ReflectionType $reflectionType) { - $phpTypeOrClass = method_exists($reflectionType, 'getName') ? $reflectionType->getName() : (string) $reflectionType; + $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : $reflectionType->__toString(); $nullable = $reflectionType->allowsNull(); - if ($reflectionType->isBuiltin()) { - if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); - } else { - $type = new Type($phpTypeOrClass, $nullable); - } + 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); + } elseif ($reflectionType->isBuiltin()) { + $type = new Type($phpTypeOrClass, $nullable); } else { $type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $phpTypeOrClass); } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php index 10b056220d..8a828c21d6 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php @@ -107,6 +107,7 @@ class ReflectionExtractorTest extends \PHPUnit_Framework_TestCase { return array( array('foo', array(new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true))), + array('buz', array(new Type(Type::BUILTIN_TYPE_NULL))), array('bar', array(new Type(Type::BUILTIN_TYPE_INT, true))), array('baz', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)))), array('donotexist', null), diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php index d93c67a3d3..e72d376c49 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php @@ -20,6 +20,10 @@ class Php71Dummy { } + public function getBuz(): void + { + } + public function setBar(?int $bar) { }