diff --git a/Extractor/ReflectionExtractor.php b/Extractor/ReflectionExtractor.php index 3306946..cbcb349 100644 --- a/Extractor/ReflectionExtractor.php +++ b/Extractor/ReflectionExtractor.php @@ -187,26 +187,26 @@ private function extractFromMutator($class, $property) $type = $this->extractFromReflectionType($reflectionType, $reflectionMethod); // HHVM reports variadics with "array" but not builtin type hints - if (!$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType()) { + if (1 === \count($type) && !$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type[0]->getBuiltinType()) { return null; } } 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); + $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()); + $type = [new Type(Type::BUILTIN_TYPE_CALLABLE, $reflectionParameter->allowsNull())]; } else { - $type = new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod)); + $type = [new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod))]; } } else { return null; } - if (\in_array($prefix, $this->arrayMutatorPrefixes)) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type); + if (1 === \count($type) && \in_array($prefix, $this->arrayMutatorPrefixes)) { + $type = [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type[0])]; } - return [$type]; + return $type; } /** @@ -225,7 +225,7 @@ private function extractFromAccessor($class, $property) } if ($this->supportsParameterType && $reflectionType = $reflectionMethod->getReturnType()) { - return [$this->extractFromReflectionType($reflectionType, $reflectionMethod)]; + return $this->extractFromReflectionType($reflectionType, $reflectionMethod); } return \in_array($prefix, ['is', 'can']) ? [new Type(Type::BUILTIN_TYPE_BOOL)] : null; @@ -234,24 +234,28 @@ private function extractFromAccessor($class, $property) /** * Extracts data from the PHP 7 reflection type. * - * @return Type + * @return Type[] */ private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionMethod $reflectionMethod) { - $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : $reflectionType->__toString(); + $types = []; $nullable = $reflectionType->allowsNull(); - 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, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); + foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) { + $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type; + + if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { + $types[] = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); + } elseif ('void' === $phpTypeOrClass || 'null' === $phpTypeOrClass) { + $types[] = new Type(Type::BUILTIN_TYPE_NULL, $nullable); + } elseif ($reflectionType->isBuiltin()) { + $types[] = new Type($phpTypeOrClass, $nullable); + } else { + $types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); + } } - return $type; + return $types; } private function resolveTypeName($name, \ReflectionMethod $reflectionMethod)