diff --git a/src/Parser/BetterReflection/AliasSourceLocator.php b/src/Parser/BetterReflection/AliasSourceLocator.php new file mode 100644 index 0000000..0344733 --- /dev/null +++ b/src/Parser/BetterReflection/AliasSourceLocator.php @@ -0,0 +1,41 @@ +isClass() || !\array_key_exists($identifier->getName(), $this->classAliases)) { + return null; + } + + return $this->redirectSourceLocator->locateIdentifier( + $reflector, + new Identifier($this->classAliases[$identifier->getName()], $identifier->getType()) + ); + } + + /** + * @inheritDoc + */ + public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array + { + return []; + } +} diff --git a/src/Parser/BetterReflection/BetterReflectionParser.php b/src/Parser/BetterReflection/BetterReflectionParser.php index 52b5fa9..f527784 100644 --- a/src/Parser/BetterReflection/BetterReflectionParser.php +++ b/src/Parser/BetterReflection/BetterReflectionParser.php @@ -25,6 +25,8 @@ class BetterReflectionParser implements ParserInterface */ private ?array $aliases = null; + private ?array $classAliases = null; + /** * @param ReaderInterface[] $sources * @param ReaderInterface[] $resolvingSources These sources are used to resolve reflections but won't generate stubs @@ -58,6 +60,9 @@ public function parse(): void ); } + $classAliases = []; + $secondarySourceLocators[] = new AliasSourceLocator($mainSourceLocator, $classAliases); + // php internals $secondarySourceLocators[] = new MemoizingSourceLocator( new PhpInternalSourceLocator($astLocator, new ReflectionSourceStubber()) @@ -74,10 +79,19 @@ public function parse(): void $aliases = []; $classIdent = new IdentifierType(IdentifierType::IDENTIFIER_CLASS); + foreach ($reflector->reflectAllClasses() as $class) { $className = $class->getName(); - $classes[$class->getNamespaceName()][$className] = new ReflectionClass($class); + $docComment = $class->getDocComment() ?? ''; + $classAliasPos = \strpos($docComment, '@alias'); + if ($classAliasPos !== false) { + $lineEnding = \strpos($docComment, "\n", $classAliasPos); + $alias = \ltrim(\substr($docComment, $classAliasPos + 7, $lineEnding - $classAliasPos - 7), '\\'); + $classAliases[$alias] = \ltrim($className, '\\'); + } + + $classes[$class->getNamespaceName()][$className] = new ReflectionClass($class); $aliases[self::TYPE_CLASS][$className] = $astLocator->getNamespaceUses($classIdent, $className); } @@ -97,6 +111,7 @@ public function parse(): void // $this->functions = $functions; // $this->constants = $constants; $this->aliases = $aliases; + $this->classAliases = $classAliases; } /** @@ -153,4 +168,16 @@ public function getAliases(string $classOrFunctionName, string $type): array return $this->aliases[$type][$classOrFunctionName]; } + + /** + * @inheritdoc + */ + public function getClassAliases(): array + { + if ($this->classAliases === null) { + throw new \BadMethodCallException('BetterReflectionParser::parse wasn\'t called yet!'); + } + + return $this->classAliases; + } } diff --git a/src/Parser/ParserInterface.php b/src/Parser/ParserInterface.php index 6be1562..2d4b0bb 100644 --- a/src/Parser/ParserInterface.php +++ b/src/Parser/ParserInterface.php @@ -44,4 +44,9 @@ public function getClasses(): array; * @throws \InvalidArgumentException If the class or function is unknown. */ public function getAliases(string $classOrFunctionName, string $type): array; + + /** + * @return array Returns a list of all class aliases in this structure: ['old-name' => 'new-name'] + */ + public function getClassAliases(): array; } diff --git a/src/PhpStubGenerator.php b/src/PhpStubGenerator.php index 93566e2..0224fe2 100644 --- a/src/PhpStubGenerator.php +++ b/src/PhpStubGenerator.php @@ -123,6 +123,16 @@ public function generate(): string } } + $classAliases = $parser->getClassAliases(); + if ($classAliases !== []) { + $result .= 'namespace' . $n + . '{' . $n; + foreach ($classAliases as $oldName => $newName) { + $result .= ' class_alias(\'' . $oldName . '\', \'' . $newName . '\');' . $n; + } + $result .= '}' . $n . $n; + } + // foreach ($parser->getFunctions() as $namespace => $functions) { // foreach ($functions as $function) { // $isGlobalNamespace = ($namespace === '');