From 3d3cf2685795a6b0cd74f1d6754a2ba51417dfaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Hansl=C3=ADk?= Date: Tue, 6 Sep 2022 09:13:08 +0200 Subject: [PATCH] PHP 8.2: Support for readonly classes --- src/Reflection/Adapter/ReflectionClass.php | 5 +++ src/Reflection/Adapter/ReflectionEnum.php | 5 +++ src/Reflection/Adapter/ReflectionObject.php | 5 +++ src/Reflection/ReflectionClass.php | 8 ++++ src/Reflection/ReflectionObject.php | 5 +++ test/unit/Fixture/ExampleClass.php | 4 ++ .../Adapter/ReflectionClassTest.php | 1 + .../Reflection/Adapter/ReflectionEnumTest.php | 1 + .../Adapter/ReflectionObjectTest.php | 1 + test/unit/Reflection/ReflectionClassTest.php | 37 +++++++++++-------- 10 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/Reflection/Adapter/ReflectionClass.php b/src/Reflection/Adapter/ReflectionClass.php index 67c70025c..b3c8fef75 100644 --- a/src/Reflection/Adapter/ReflectionClass.php +++ b/src/Reflection/Adapter/ReflectionClass.php @@ -308,6 +308,11 @@ public function isFinal(): bool return $this->betterReflectionClass->isFinal(); } + public function isReadOnly(): bool + { + return $this->betterReflectionClass->isReadOnly(); + } + public function getModifiers(): int { return $this->betterReflectionClass->getModifiers(); diff --git a/src/Reflection/Adapter/ReflectionEnum.php b/src/Reflection/Adapter/ReflectionEnum.php index b345ca579..2b39ab142 100644 --- a/src/Reflection/Adapter/ReflectionEnum.php +++ b/src/Reflection/Adapter/ReflectionEnum.php @@ -295,6 +295,11 @@ public function isFinal(): bool return $this->betterReflectionEnum->isFinal(); } + public function isReadOnly(): bool + { + return $this->betterReflectionEnum->isReadOnly(); + } + public function getModifiers(): int { return $this->betterReflectionEnum->getModifiers(); diff --git a/src/Reflection/Adapter/ReflectionObject.php b/src/Reflection/Adapter/ReflectionObject.php index e1480e7f1..2ac261082 100644 --- a/src/Reflection/Adapter/ReflectionObject.php +++ b/src/Reflection/Adapter/ReflectionObject.php @@ -258,6 +258,11 @@ public function isFinal(): bool return $this->betterReflectionObject->isFinal(); } + public function isReadOnly(): bool + { + return $this->betterReflectionObject->isReadOnly(); + } + public function getModifiers(): int { return $this->betterReflectionObject->getModifiers(); diff --git a/src/Reflection/ReflectionClass.php b/src/Reflection/ReflectionClass.php index 68a4e58bf..4b332f78e 100644 --- a/src/Reflection/ReflectionClass.php +++ b/src/Reflection/ReflectionClass.php @@ -62,6 +62,8 @@ class ReflectionClass implements Reflection { + public const IS_READONLY = 65536; + public const ANONYMOUS_CLASS_NAME_PREFIX = 'class@anonymous'; public const ANONYMOUS_CLASS_NAME_PREFIX_REGEXP = '~^(?:class|[\w\\\\]+)@anonymous~'; private const ANONYMOUS_CLASS_NAME_SUFFIX = '@anonymous'; @@ -1055,6 +1057,11 @@ public function isFinal(): bool return $this->node instanceof ClassNode && $this->node->isFinal(); } + public function isReadOnly(): bool + { + return $this->node instanceof ClassNode && $this->node->isReadonly(); + } + /** * Get the core-reflection-compatible modifier values. */ @@ -1062,6 +1069,7 @@ public function getModifiers(): int { $val = $this->isAbstract() ? CoreReflectionClass::IS_EXPLICIT_ABSTRACT : 0; $val += $this->isFinal() ? CoreReflectionClass::IS_FINAL : 0; + $val += $this->isReadOnly() ? self::IS_READONLY : 0; return $val; } diff --git a/src/Reflection/ReflectionObject.php b/src/Reflection/ReflectionObject.php index a2e29d735..f604c726f 100644 --- a/src/Reflection/ReflectionObject.php +++ b/src/Reflection/ReflectionObject.php @@ -352,6 +352,11 @@ public function isFinal(): bool return $this->reflectionClass->isFinal(); } + public function isReadOnly(): bool + { + return $this->reflectionClass->isReadOnly(); + } + public function getModifiers(): int { return $this->reflectionClass->getModifiers(); diff --git a/test/unit/Fixture/ExampleClass.php b/test/unit/Fixture/ExampleClass.php index f2f831f59..fce5d620d 100644 --- a/test/unit/Fixture/ExampleClass.php +++ b/test/unit/Fixture/ExampleClass.php @@ -68,6 +68,10 @@ final class FinalClass { } + readonly class ReadOnlyClass + { + } + trait ExampleTrait { } diff --git a/test/unit/Reflection/Adapter/ReflectionClassTest.php b/test/unit/Reflection/Adapter/ReflectionClassTest.php index 036431fc6..5a756a733 100644 --- a/test/unit/Reflection/Adapter/ReflectionClassTest.php +++ b/test/unit/Reflection/Adapter/ReflectionClassTest.php @@ -98,6 +98,7 @@ public function methodExpectationProvider(): array ['isTrait', [], true, null, true, null], ['isAbstract', [], true, null, true, null], ['isFinal', [], true, null, true, null], + ['isReadOnly', [], true, null, true, null], ['getModifiers', [], 123, null, 123, null], ['isInstance', [new stdClass()], true, null, true, null], ['newInstance', [], null, NotImplemented::class, null, null], diff --git a/test/unit/Reflection/Adapter/ReflectionEnumTest.php b/test/unit/Reflection/Adapter/ReflectionEnumTest.php index 47d86844a..f53173599 100644 --- a/test/unit/Reflection/Adapter/ReflectionEnumTest.php +++ b/test/unit/Reflection/Adapter/ReflectionEnumTest.php @@ -105,6 +105,7 @@ public function methodExpectationProvider(): array ['isTrait', [], true, null, true, null], ['isAbstract', [], true, null, true, null], ['isFinal', [], true, null, true, null], + ['isReadOnly', [], true, null, true, null], ['getModifiers', [], 123, null, 123, null], ['isInstance', [new stdClass()], true, null, true, null], ['newInstance', [], null, NotImplemented::class, null, null], diff --git a/test/unit/Reflection/Adapter/ReflectionObjectTest.php b/test/unit/Reflection/Adapter/ReflectionObjectTest.php index 4610f32ca..4db0ccfce 100644 --- a/test/unit/Reflection/Adapter/ReflectionObjectTest.php +++ b/test/unit/Reflection/Adapter/ReflectionObjectTest.php @@ -97,6 +97,7 @@ public function methodExpectationProvider(): array ['isTrait', [], true, null, true, null], ['isAbstract', [], true, null, true, null], ['isFinal', [], true, null, true, null], + ['isReadOnly', [], true, null, true, null], ['getModifiers', [], 123, null, 123, null], ['isInstance', [new stdClass()], true, null, true, null], ['newInstance', [], null, NotImplemented::class, null, null], diff --git a/test/unit/Reflection/ReflectionClassTest.php b/test/unit/Reflection/ReflectionClassTest.php index de3ae9cbe..45c902dd4 100644 --- a/test/unit/Reflection/ReflectionClassTest.php +++ b/test/unit/Reflection/ReflectionClassTest.php @@ -16,7 +16,6 @@ use PhpParser\Node\Stmt\Class_; use PHPUnit\Framework\TestCase; use Qux; -use Reflection as CoreReflection; use ReflectionClass as CoreReflectionClass; use ReflectionMethod as CoreReflectionMethod; use ReflectionProperty as CoreReflectionProperty; @@ -74,6 +73,7 @@ use Roave\BetterReflectionTest\Fixture\InvalidInheritances; use Roave\BetterReflectionTest\Fixture\MethodsOrder; use Roave\BetterReflectionTest\Fixture\PureEnum; +use Roave\BetterReflectionTest\Fixture\ReadOnlyClass; use Roave\BetterReflectionTest\Fixture\StaticProperties; use Roave\BetterReflectionTest\Fixture\StaticPropertyGetSet; use Roave\BetterReflectionTest\Fixture\StringEnum; @@ -1130,22 +1130,33 @@ public function testIsFinalForEnum(): void self::assertTrue($classInfo->isFinal()); } - /** @return list}> */ + public function testIsReadOnly(): void + { + $reflector = new DefaultReflector(new SingleFileSourceLocator( + __DIR__ . '/../Fixture/ExampleClass.php', + $this->astLocator, + )); + + $classInfo = $reflector->reflectClass(ReadOnlyClass::class); + self::assertTrue($classInfo->isReadOnly()); + + $classInfo = $reflector->reflectClass(ExampleClass::class); + self::assertFalse($classInfo->isReadOnly()); + } + + /** @return list */ public function modifierProvider(): array { return [ - ['ExampleClass', 0, []], - ['AbstractClass', CoreReflectionClass::IS_EXPLICIT_ABSTRACT, ['abstract']], - ['FinalClass', CoreReflectionClass::IS_FINAL, ['final']], + ['ExampleClass', 0], + ['AbstractClass', CoreReflectionClass::IS_EXPLICIT_ABSTRACT], + ['FinalClass', CoreReflectionClass::IS_FINAL], + ['ReadOnlyClass', ReflectionClass::IS_READONLY], ]; } - /** - * @param list $expectedModifierNames - * - * @dataProvider modifierProvider - */ - public function testGetModifiers(string $className, int $expectedModifier, array $expectedModifierNames): void + /** @dataProvider modifierProvider */ + public function testGetModifiers(string $className, int $expectedModifier): void { $reflector = new DefaultReflector(new SingleFileSourceLocator( __DIR__ . '/../Fixture/ExampleClass.php', @@ -1155,10 +1166,6 @@ public function testGetModifiers(string $className, int $expectedModifier, array $classInfo = $reflector->reflectClass('\Roave\BetterReflectionTest\Fixture\\' . $className); self::assertSame($expectedModifier, $classInfo->getModifiers()); - self::assertSame( - $expectedModifierNames, - CoreReflection::getModifierNames($classInfo->getModifiers()), - ); } public function testIsTrait(): void