Skip to content

Commit

Permalink
PHP 8.2: Support for readonly classes
Browse files Browse the repository at this point in the history
  • Loading branch information
kukulich committed Sep 6, 2022
1 parent 32156af commit 3d3cf26
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 15 deletions.
5 changes: 5 additions & 0 deletions src/Reflection/Adapter/ReflectionClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions src/Reflection/Adapter/ReflectionEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions src/Reflection/Adapter/ReflectionObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
8 changes: 8 additions & 0 deletions src/Reflection/ReflectionClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -1055,13 +1057,19 @@ 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.
*/
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;
}
Expand Down
5 changes: 5 additions & 0 deletions src/Reflection/ReflectionObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
4 changes: 4 additions & 0 deletions test/unit/Fixture/ExampleClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ final class FinalClass
{
}

readonly class ReadOnlyClass
{
}

trait ExampleTrait
{
}
Expand Down
1 change: 1 addition & 0 deletions test/unit/Reflection/Adapter/ReflectionClassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
1 change: 1 addition & 0 deletions test/unit/Reflection/Adapter/ReflectionEnumTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
1 change: 1 addition & 0 deletions test/unit/Reflection/Adapter/ReflectionObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
37 changes: 22 additions & 15 deletions test/unit/Reflection/ReflectionClassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1130,22 +1130,33 @@ public function testIsFinalForEnum(): void
self::assertTrue($classInfo->isFinal());
}

/** @return list<array{0: string, 1: int, 2: list<string>}> */
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<array{0: string, 1: int}> */
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<string> $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',
Expand All @@ -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
Expand Down

0 comments on commit 3d3cf26

Please sign in to comment.