diff --git a/src/Utils/Type.php b/src/Utils/Type.php index 965977bc4..10ec31fb7 100644 --- a/src/Utils/Type.php +++ b/src/Utils/Type.php @@ -29,27 +29,33 @@ final class Type */ public static function fromReflection( \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection, + ?\ReflectionClass $staticClass = null, ): ?self { $type = $reflection instanceof \ReflectionFunctionAbstract ? $reflection->getReturnType() ?? (PHP_VERSION_ID >= 80100 && $reflection instanceof \ReflectionMethod ? $reflection->getTentativeReturnType() : null) : $reflection->getType(); - return $type ? self::fromReflectionType($type, $reflection, true) : null; + return $type ? self::fromReflectionType($type, $reflection, true, $staticClass) : null; } - private static function fromReflectionType(\ReflectionType $type, $of, bool $asObject): self|string + private static function fromReflectionType( + \ReflectionType $type, + $of, + bool $asObject, + ?\ReflectionClass $staticClass, + ): self|string { if ($type instanceof \ReflectionNamedType) { - $name = self::resolve($type->getName(), $of); + $name = self::resolve($type->getName(), $of, $staticClass); return $asObject ? new self($type->allowsNull() && $name !== 'mixed' ? [$name, 'null'] : [$name]) : $name; } elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) { return new self( - array_map(fn($t) => self::fromReflectionType($t, $of, false), $type->getTypes()), + array_map(fn($t) => self::fromReflectionType($t, $of, false, $staticClass), $type->getTypes()), $type instanceof \ReflectionUnionType ? '|' : '&', ); @@ -90,13 +96,16 @@ public static function fromString(string $type): self public static function resolve( string $type, \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $of, + ?\ReflectionClass $staticClass = null, ): string { $lower = strtolower($type); if ($of instanceof \ReflectionFunction) { return $type; - } elseif ($lower === 'self' || $lower === 'static') { + } elseif ($lower === 'self') { return $of->getDeclaringClass()->name; + } elseif ($lower === 'static') { + return ($staticClass ?? $of->getDeclaringClass())->name; } elseif ($lower === 'parent' && $of->getDeclaringClass()->getParentClass()) { return $of->getDeclaringClass()->getParentClass()->name; } else { diff --git a/tests/Utils/Type.fromReflection.method.phpt b/tests/Utils/Type.fromReflection.method.phpt index 43e0cedad..01681cd72 100644 --- a/tests/Utils/Type.fromReflection.method.phpt +++ b/tests/Utils/Type.fromReflection.method.phpt @@ -37,3 +37,19 @@ $type = Type::fromReflection((new ReflectionObject($class))->getMethod('foo')); Assert::same([$class::class], $type->getNames()); Assert::same($class::class, (string) $type); + + +class ParentClass +{ + public function foo(): static + { + } +} + +class ChildClass extends ParentClass +{ +} + +$type = Type::fromReflection(new ReflectionMethod(ChildClass::class, 'foo'), new ReflectionClass(ChildClass::class)); +Assert::same([ChildClass::class], $type->getNames()); +Assert::same(ChildClass::class, (string) $type);