8000 [PropertyInfo] Fix edge cases in ReflectionExtractor · symfony/symfony@6a000dc · GitHub
[go: up one dir, main page]

Skip to content

Commit 6a000dc

Browse files
[PropertyInfo] Fix edge cases in ReflectionExtractor
1 parent 7f0ae27 commit 6a000dc

File tree

2 files changed

+50
-57
lines changed

2 files changed

+50
-57
lines changed

src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php

-56Lines changed: 49 additions & 56 deletions
227
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
4444
*/
4545
public static $arrayMutatorPrefixes = array('add', 'remove');
4646

47+
private $supportsParameterType;
48+
private $supportsCallable;
49+
50+
public function __construct()
51+
{
52+
$this->supportsParameterType = method_exists('ReflectionParameter', 'getType');
53+
$this->supportsCallable = method_exists('ReflectionParameter', 'isCallable');
54+
}
55+
4756
/**
4857
* {@inheritdoc}
4958
*/
@@ -131,71 +140,57 @@ private function extractFromMutator($class, $property)
131140
return;
132141
}
133142

143+
$collection = $phpType = $typeClass = $collectionKeyType = $collectionValueType = null;
134144
$reflectionParameters = $reflectionMethod->getParameters();
135145
$reflectionParameter = $reflectionParameters[0];
136-
146+
$nullable = $reflectionParameter->allowsNull();
137147
$arrayMutator = in_array($prefix, self::$arrayMutatorPrefixes);
138148

139-
if (method_exists($reflectionParameter, 'getType') && $reflectionType = $reflectionParameter->getType()) {
140-
$fromReflectionType = $this->extractFromReflectionType($reflectionType);
149+
if ($this->supportsParameterType) {
150+
if ($reflectionType = $reflectionParameter->getType()) {
151+
$fromReflectionType = $this->extractFromReflectionType($reflectionType);
141152

142-
if (!$arrayMutator) {
143-
return array($fromReflectionType);
153+
// HHVM reports not-builtin-"array" as type hints for variadics
154+
if ($reflectionType->isBuiltin() || Type::BUILTIN_TYPE_ARRAY !== $fromReflectionType->getBuiltinType()) {
155+
if (!$arrayMutator) {
156+
return array($fromReflectionType);
157+
}
158+
$collectionValueType = $fromReflectionType;
159+
}
144160
}
145-
146-
$phpType = Type::BUILTIN_TYPE_ARRAY;
147-
$collectionKeyType = new Type(Type::BUILTIN_TYPE_INT);
148-
$collectionValueType = $fromReflectionType;
149-
}
150-
151-
if ($reflectionParameter->isArray()) {
161+
} elseif ($reflectionParameter->isArray()) {
152162
$phpType = Type::BUILTIN_TYPE_ARRAY;
153163
$collection = true;
164+
} elseif ($this->supportsCallable && $reflectionParameter->isCallable()) {
165+
$phpType = Type::BUILTIN_TYPE_CALLABLE;
166+
} else {
167+
try {
168+
if ($typeClass = $reflectionParameter->getClass()) {
169+
$typeClass = $typeClass->name;
170+
}
171+
} catch (\ReflectionException $e) {
172+
// mandatory; extract it from the exception message
173+
$typeClass = str_replace(array('Class ', ' does not exist'), '', $e->getMessage());
174+
}
175+
if ($typeClass) {
176+
$phpType = Type::BUILTIN_TYPE_OBJECT;
177+
}
154178
}
155179

156180
if ($arrayMutator) {
157181
$collection = true;
158182
$nullable = false;
159-
$collectionNullable = $reflectionParameter->allowsNull();
160-
} else {
161-
$nullable = $reflectionParameter->allowsNull();
162-
$collectionNullable = false;
163-
}
164-
165-
if (!isset($collection)) {
166-
$collection = false;
167-
}
168-
169-
if (method_exists($reflectionParameter, 'isCallable') && $reflectionParameter->isCallable()) {
170-
$phpType = Type::BUILTIN_TYPE_CALLABLE;
171-
}
172-
173-
if ($typeHint = $reflectionParameter->getClass()) {
174-
if ($collection) {
175-
$phpType = Type::BUILTIN_TYPE_ARRAY;
176-
$collectionKeyType = new Type(Type::BUILTIN_TYPE_INT);
177-
$collectionValueType = new Type(Type::BUILTIN_TYPE_OBJECT, $collectionNullable, $typeHint->name);
178-
} else {
179-
$phpType = Type::BUILTIN_TYPE_OBJECT;
180-
$typeClass = $typeHint->name;
183+
if ($phpType) {
184+
$collectionValueType = new Type($phpType, $nullable, $typeClass);
185+
$typeClass = null;
181186
}
187+
$phpType = Type::BUILTIN_TYPE_ARRAY;
188+
$collectionKeyType = new Type(Type::BUILTIN_TYPE_INT);
182189
}
183190

184-
// Nothing useful extracted
185-
if (!isset($phpType)) {
186-
return;
191+
if ($phpType) {
192+
return array(new Type($phpType, $nullable, $typeClass, $collection, $collectionKeyType, $collectionValueType));
187193
}
188-
189-
return array(
190-
new Type(
191-
$phpType,
192-
$nullable,
193-
isset($typeClass) ? $typeClass : null,
194-
$collection,
195-
isset($collectionKeyType) ? $collectionKeyType : null,
196-
isset($collectionValueType) ? $collectionValueType : null
197-
),
198-
);
199194
}
200195

201196
/**
@@ -213,7 +208,7 @@ private function extractFromAccessor($class, $property)
213208
return;
214209
}
215210

216-
if (method_exists($reflectionMethod, 'getReturnType') && $reflectionType = $reflectionMethod->getReturnType()) {
211+
if ($this->supportsParameterType && $reflectionType = $reflectionMethod->getReturnType()) {
217212
return array($this->extractFromReflectionType($reflectionType));
218213
}
219214

@@ -231,15 +226,13 @@ private function extractFromAccessor($class, $property)
231226
*/
232
private function extractFromReflectionType(\ReflectionType $reflectionType)
233228
{
234-
$phpTypeOrClass = method_exists($reflectionType, 'getName') ? $reflectionType->getName() : (string) $reflectionType;
229+
$phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : $reflectionType->__toString();
235230
$nullable = $reflectionType->allowsNull();
236231

237-
if ($reflectionType->isBuiltin()) {
238-
if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) {
239-
$type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true);
240-
} else {
241-
$type = new Type($phpTypeOrClass, $nullable);
242-
}
232+
if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) {
233+
$type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true);
234+
} elseif ($reflectionType->isBuiltin()) {
235+
$type = new Type($phpTypeOrClass, $nullable);
243236
} else {
244237
$type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $phpTypeOrClass);
245238
}

src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function typesProvider()
6969
array('b', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy'))),
7070
array('c', array(new Type(Type::BUILTIN_TYPE_BOOL))),
7171
array('d', array(new Type(Type::BUILTIN_TYPE_BOOL))),
72-
array('e', null),
72+
array('e', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT)))),
7373
array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')))),
7474
array('donotexist', null),
7575
);

0 commit comments

Comments
 (0)
0