protected function expandType(ClassReflection $class, $type)
{
// expand "SomeType<SomeElementType>" to "\SomeTypeNamespace\SomeType<\ElementTypeNamespace\ElementType>"
if (strpos($type, '<') !== false) {
$typeParts = explode('<', $type);
$type = $typeParts[0];
$elementType = rtrim($typeParts[1], '>');
return $this->expandType($class, $type) . '<' . $this->expandType($class, $elementType) . '>';
}
// skip simple types and types with fully qualified namespaces
if ($type === 'mixed' || $type[0] === '\\' || TypeHandling::isSimpleType($type)) {
return TypeHandling::normalizeType($type);
}
// we try to find the class relative to the current namespace...
$possibleFullyQualifiedClassName = sprintf('%s\\%s', $class->getNamespaceName(), $type);
if (class_exists($possibleFullyQualifiedClassName) || interface_exists($possibleFullyQualifiedClassName)) {
return $possibleFullyQualifiedClassName;
}
// and then we try to find "use" statements for the class.
$className = $class->getName();
if (!isset($this->useStatementsForClassCache[$className])) {
$this->useStatementsForClassCache[$className] = $this->getDoctrinePhpParser()->parseClass($class);
}
$useStatementsForClass = $this->useStatementsForClassCache[$className];
// ... and try to expand them
$typeParts = explode('\\', $type, 2);
$lowercasedFirstTypePart = strtolower($typeParts[0]);
if (isset($useStatementsForClass[$lowercasedFirstTypePart])) {
$typeParts[0] = $useStatementsForClass[$lowercasedFirstTypePart];
return implode('\\', $typeParts);
}
return $type;
}