Skip to content

Commit d0c9955

Browse files
authored
Merge pull request #1521 from kukulich/php85
PHP 8.5 features
2 parents 15f7230 + 4e0bcad commit d0c9955

File tree

11 files changed

+239
-14
lines changed

11 files changed

+239
-14
lines changed

src/NodeCompiler/CompileNodeToValue.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,30 @@ public function __invoke(Node $node, CompilerContext $context): CompiledValue
140140
return $this->getEnumPropertyValue($node, $context);
141141
}
142142

143+
if ($node instanceof Node\Expr\Cast\Int_) {
144+
return (int) $this($node->expr, $context)->value;
145+
}
146+
147+
if ($node instanceof Node\Expr\Cast\Double) {
148+
return (float) $this($node->expr, $context)->value;
149+
}
150+
151+
if ($node instanceof Node\Expr\Cast\Bool_) {
152+
return (bool) $this($node->expr, $context)->value;
153+
}
154+
155+
if ($node instanceof Node\Expr\Cast\String_) {
156+
return (string) $this($node->expr, $context)->value;
157+
}
158+
159+
if ($node instanceof Node\Expr\Cast\Array_) {
160+
return (array) $this($node->expr, $context)->value;
161+
}
162+
163+
if ($node instanceof Node\Expr\Cast\Object_) {
164+
return (object) $this($node->expr, $context)->value;
165+
}
166+
143167
throw Exception\UnableToCompileNode::forUnRecognizedExpressionInContext($node, $context);
144168
});
145169

src/Reflection/Adapter/ReflectionAttribute.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
/** @template-extends CoreReflectionAttribute<object> */
1515
final class ReflectionAttribute extends CoreReflectionAttribute
1616
{
17+
public const TARGET_CONSTANT_COMPATIBILITY = 64;
18+
1719
public function __construct(private BetterReflectionAttribute $betterReflectionAttribute)
1820
{
1921
unset($this->name);
@@ -26,7 +28,7 @@ public function getName(): string
2628
}
2729

2830
/**
29-
* @return int-mask-of<Attribute::TARGET_*>
31+
* @return int-mask-of<Attribute::TARGET_*>|self::TARGET_CONSTANT_COMPATIBILITY
3032
*
3133
* @psalm-mutation-free
3234
* @psalm-suppress ImplementedReturnTypeMismatch

src/Reflection/Adapter/ReflectionProperty.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use ReflectionException as CoreReflectionException;
1111
use ReflectionMethod as CoreReflectionMethod;
1212
use ReflectionProperty as CoreReflectionProperty;
13-
use Roave\BetterReflection\Reflection\Adapter\Exception\NotImplemented;
1413
use Roave\BetterReflection\Reflection\Exception\NoObjectProvided;
1514
use Roave\BetterReflection\Reflection\Exception\NotAnObject;
1615
use Roave\BetterReflection\Reflection\ReflectionAttribute as BetterReflectionAttribute;
@@ -359,6 +358,21 @@ public function __get(string $name): mixed
359358

360359
public function getMangledName(): string
361360
{
362-
throw new NotImplemented('Not implemented');
361+
if ($this->betterReflectionProperty->isPrivate()) {
362+
return sprintf(
363+
"\0%s\0%s",
364+
$this->betterReflectionProperty->getDeclaringClass()->getName(),
365+
$this->betterReflectionProperty->getName(),
366+
);
367+
}
368+
369+
if ($this->betterReflectionProperty->isProtected()) {
370+
return sprintf(
371+
"\0*\0%s",
372+
$this->betterReflectionProperty->getName(),
373+
);
374+
}
375+
376+
return $this->betterReflectionProperty->getName();
363377
}
364378
}

src/Reflection/Attribute/ReflectionAttributeHelper.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Roave\BetterReflection\Reflection\ReflectionAttribute;
99
use Roave\BetterReflection\Reflection\ReflectionClass;
1010
use Roave\BetterReflection\Reflection\ReflectionClassConstant;
11+
use Roave\BetterReflection\Reflection\ReflectionConstant;
1112
use Roave\BetterReflection\Reflection\ReflectionEnumCase;
1213
use Roave\BetterReflection\Reflection\ReflectionFunction;
1314
use Roave\BetterReflection\Reflection\ReflectionMethod;
@@ -31,7 +32,7 @@ class ReflectionAttributeHelper
3132
*/
3233
public static function createAttributes(
3334
Reflector $reflector,
34-
ReflectionClass|ReflectionMethod|ReflectionFunction|ReflectionClassConstant|ReflectionEnumCase|ReflectionProperty|ReflectionParameter $reflection,
35+
ReflectionClass|ReflectionMethod|ReflectionFunction|ReflectionConstant|ReflectionClassConstant|ReflectionEnumCase|ReflectionProperty|ReflectionParameter $reflection,
3536
array $attrGroups,
3637
): array {
3738
$repeated = [];

src/Reflection/Deprecated/DeprecatedHelper.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
namespace Roave\BetterReflection\Reflection\Deprecated;
66

7+
use Deprecated;
78
use Roave\BetterReflection\Reflection\Annotation\AnnotationHelper;
89
use Roave\BetterReflection\Reflection\Attribute\ReflectionAttributeHelper;
910
use Roave\BetterReflection\Reflection\ReflectionClass;
1011
use Roave\BetterReflection\Reflection\ReflectionClassConstant;
12+
use Roave\BetterReflection\Reflection\ReflectionConstant;
1113
use Roave\BetterReflection\Reflection\ReflectionEnumCase;
1214
use Roave\BetterReflection\Reflection\ReflectionFunction;
1315
use Roave\BetterReflection\Reflection\ReflectionMethod;
@@ -17,10 +19,9 @@
1719
final class DeprecatedHelper
1820
{
1921
/** @psalm-pure */
20-
public static function isDeprecated(ReflectionClass|ReflectionMethod|ReflectionFunction|ReflectionClassConstant|ReflectionEnumCase|ReflectionProperty $reflection): bool
22+
public static function isDeprecated(ReflectionClass|ReflectionMethod|ReflectionFunction|ReflectionConstant|ReflectionClassConstant|ReflectionEnumCase|ReflectionProperty $reflection): bool
2123
{
22-
// We don't use Deprecated::class because the class is currently missing in stubs
23-
if (ReflectionAttributeHelper::filterAttributesByName($reflection->getAttributes(), 'Deprecated') !== []) {
24+
if (ReflectionAttributeHelper::filterAttributesByName($reflection->getAttributes(), Deprecated::class) !== []) {
2425
return true;
2526
}
2627

src/Reflection/ReflectionAttribute.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpParser\Node;
99
use Roave\BetterReflection\NodeCompiler\CompileNodeToValue;
1010
use Roave\BetterReflection\NodeCompiler\CompilerContext;
11+
use Roave\BetterReflection\Reflection\Adapter\ReflectionAttribute as ReflectionAttributeAdapter;
1112
use Roave\BetterReflection\Reflection\StringCast\ReflectionAttributeStringCast;
1213
use Roave\BetterReflection\Reflector\Reflector;
1314

@@ -26,7 +27,7 @@ class ReflectionAttribute
2627
public function __construct(
2728
private Reflector $reflector,
2829
Node\Attribute $node,
29-
private ReflectionClass|ReflectionMethod|ReflectionFunction|ReflectionClassConstant|ReflectionEnumCase|ReflectionProperty|ReflectionParameter $owner,
30+
private ReflectionClass|ReflectionMethod|ReflectionFunction|ReflectionConstant|ReflectionClassConstant|ReflectionEnumCase|ReflectionProperty|ReflectionParameter $owner,
3031
private bool $isRepeated,
3132
) {
3233
/** @var class-string $name */
@@ -43,7 +44,7 @@ public function __construct(
4344
}
4445

4546
/** @internal */
46-
public function withOwner(ReflectionClass|ReflectionMethod|ReflectionFunction|ReflectionClassConstant|ReflectionEnumCase|ReflectionProperty|ReflectionParameter $owner): self
47+
public function withOwner(ReflectionClass|ReflectionMethod|ReflectionFunction|ReflectionConstant|ReflectionClassConstant|ReflectionEnumCase|ReflectionProperty|ReflectionParameter $owner): self
4748
{
4849
$clone = clone $this;
4950
$clone->owner = $owner;
@@ -77,12 +78,13 @@ public function getArguments(): array
7778
return array_map(static fn (Node\Expr $value): mixed => $compiler->__invoke($value, $context)->value, $this->arguments);
7879
}
7980

80-
/** @return int-mask-of<Attribute::TARGET_*> */
81+
/** @return int-mask-of<Attribute::TARGET_*>|ReflectionAttributeAdapter::TARGET_CONSTANT_COMPATIBILITY */
8182
public function getTarget(): int
8283
{
8384
return match (true) {
8485
$this->owner instanceof ReflectionClass => Attribute::TARGET_CLASS,
8586
$this->owner instanceof ReflectionFunction => Attribute::TARGET_FUNCTION,
87+
$this->owner instanceof ReflectionConstant => ReflectionAttributeAdapter::TARGET_CONSTANT_COMPATIBILITY,
8688
$this->owner instanceof ReflectionMethod => Attribute::TARGET_METHOD,
8789
$this->owner instanceof ReflectionProperty => Attribute::TARGET_PROPERTY,
8890
$this->owner instanceof ReflectionClassConstant => Attribute::TARGET_CLASS_CONSTANT,

src/Reflection/ReflectionConstant.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
use Roave\BetterReflection\NodeCompiler\CompiledValue;
1010
use Roave\BetterReflection\NodeCompiler\CompileNodeToValue;
1111
use Roave\BetterReflection\NodeCompiler\CompilerContext;
12-
use Roave\BetterReflection\Reflection\Annotation\AnnotationHelper;
12+
use Roave\BetterReflection\Reflection\Attribute\ReflectionAttributeHelper;
13+
use Roave\BetterReflection\Reflection\Deprecated\DeprecatedHelper;
1314
use Roave\BetterReflection\Reflection\Exception\InvalidConstantNode;
1415
use Roave\BetterReflection\Reflection\StringCast\ReflectionConstantStringCast;
1516
use Roave\BetterReflection\Reflector\Exception\IdentifierNotFound;
@@ -58,6 +59,9 @@ class ReflectionConstant implements Reflection
5859
/** @var positive-int */
5960
private int $endColumn;
6061

62+
/** @var list<ReflectionAttribute> */
63+
private array $attributes;
64+
6165
/** @psalm-allow-private-mutation */
6266
private CompiledValue|null $compiledValue = null;
6367

@@ -82,6 +86,9 @@ private function __construct(
8286
}
8387

8488
$this->docComment = GetLastDocComment::forNode($node);
89+
$this->attributes = $node instanceof Node\Stmt\Const_
90+
? ReflectionAttributeHelper::createAttributes($reflector, $this, $node->attrGroups)
91+
: [];
8592

8693
$startLine = $node->getStartLine();
8794
assert($startLine > 0);
@@ -227,7 +234,7 @@ public function isUserDefined(): bool
227234

228235
public function isDeprecated(): bool
229236
{
230-
return AnnotationHelper::isDeprecated($this->getDocComment());
237+
return DeprecatedHelper::isDeprecated($this);
231238
}
232239

233240
public function getValueExpression(): Node\Expr
@@ -305,6 +312,28 @@ public function __toString(): string
305312
return ReflectionConstantStringCast::toString($this);
306313
}
307314

315+
/** @return list<ReflectionAttribute> */
316+
public function getAttributes(): array
317+
{
318+
return $this->attributes;
319+
}
320+
321+
/** @return list<ReflectionAttribute> */
322+
public function getAttributesByName(string $name): array
323+
{
324+
return ReflectionAttributeHelper::filterAttributesByName($this->getAttributes(), $name);
325+
}
326+
327+
/**
328+
* @param class-string $className
329+
*
330+
* @return list<ReflectionAttribute>
331+
*/
332+
public function getAttributesByInstance(string $className): array
333+
{
334+
return ReflectionAttributeHelper::filterAttributesByInstance($this->getAttributes(), $className);
335+
}
336+
308337
private function setNamesFromNode(Node\Stmt\Const_|Node\Expr\FuncCall $node, int|null $positionInNode): void
309338
{
310339
if ($node instanceof Node\Expr\FuncCall) {

test/unit/Fixture/Attributes.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
use Attribute;
66

7-
const SOME_CONSTANT = 'some-constant';
8-
97
#[Attribute]
108
class Attr
119
{
@@ -16,6 +14,10 @@ class AnotherAttr extends Attr
1614
{
1715
}
1816

17+
#[Attr]
18+
#[AnotherAttr]
19+
const SOME_CONSTANT = 'some-constant';
20+
1921
#[Attr]
2022
#[AnotherAttr]
2123
class ClassWithAttributes

test/unit/NodeCompiler/CompileNodeToValueTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
use Roave\BetterReflectionTest\Fixture\MagicConstantsClass;
3737
use Roave\BetterReflectionTest\Fixture\MagicConstantsInPropertyHooks;
3838
use Roave\BetterReflectionTest\Fixture\MagicConstantsTrait;
39+
use stdClass;
3940

4041
use function assert;
4142
use function define;
@@ -200,6 +201,11 @@ public static function nodeProvider(): array
200201
['4 <=> 1', 1],
201202
['1 <=> 1', 0],
202203
['5 ?? 4', 5],
204+
['(int) true', 1],
205+
['(float) true', 1.0],
206+
['(string) true', '1'],
207+
['(bool) 1', true],
208+
['(array) 1', [1]],
203209
];
204210
}
205211

@@ -1127,6 +1133,15 @@ public function testMagicConstantsInPropertyHooks(string $propertyName, mixed $e
11271133
self::assertSame($expectedValue, $getHookParameterAttribute->getArguments()[0]);
11281134
}
11291135

1136+
public function testObjectCast(): void
1137+
{
1138+
$node = $this->parseCode('(object) []');
1139+
1140+
$compiledValue = (new CompileNodeToValue())->__invoke($node, $this->getDummyContext());
1141+
1142+
self::assertInstanceOf(stdClass::class, $compiledValue->value);
1143+
}
1144+
11301145
/** @return non-empty-string */
11311146
private static function realPath(string $path): string
11321147
{

test/unit/Reflection/Adapter/ReflectionPropertyTest.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,4 +640,79 @@ public function testGetRawValue(): void
640640
$reflectionPropertyAdapter = new ReflectionPropertyAdapter($betterReflectionProperty);
641641
$reflectionPropertyAdapter->getRawValue(new stdClass());
642642
}
643+
644+
public function testGetMangledNameForPublicProperty(): void
645+
{
646+
$betterReflectionClass = $this->createMock(BetterReflectionClass::class);
647+
$betterReflectionClass
648+
->method('getName')
649+
->willReturn('Foo');
650+
651+
$betterReflectionProperty = $this->createMock(BetterReflectionProperty::class);
652+
$betterReflectionProperty
653+
->method('getDeclaringClass')
654+
->willReturn($betterReflectionClass);
655+
$betterReflectionProperty
656+
->method('getName')
657+
->willReturn('publicProperty');
658+
$betterReflectionProperty
659+
->method('isPrivate')
660+
->willReturn(false);
661+
$betterReflectionProperty
662+
->method('isProtected')
663+
->willReturn(false);
664+
665+
$reflectionPropertyAdapter = new ReflectionPropertyAdapter($betterReflectionProperty);
666+
self::assertSame('publicProperty', $reflectionPropertyAdapter->getMangledName());
667+
}
668+
669+
public function testGetMangledNameForProtectedProperty(): void
670+
{
671+
$betterReflectionClass = $this->createMock(BetterReflectionClass::class);
672+
$betterReflectionClass
673+
->method('getName')
674+
->willReturn('Foo');
675+
676+
$betterReflectionProperty = $this->createMock(BetterReflectionProperty::class);
677+
$betterReflectionProperty
678+
->method('getDeclaringClass')
679+
->willReturn($betterReflectionClass);
680+
$betterReflectionProperty
681+
->method('getName')
682+
->willReturn('protectedProperty');
683+
$betterReflectionProperty
684+
->method('isPrivate')
685+
->willReturn(false);
686+
$betterReflectionProperty
687+
->method('isProtected')
688+
->willReturn(true);
689+
690+
$reflectionPropertyAdapter = new ReflectionPropertyAdapter($betterReflectionProperty);
691+
self::assertSame("\0*\0protectedProperty", $reflectionPropertyAdapter->getMangledName());
692+
}
693+
694+
public function testGetMangledNameForPrivateProperty(): void
695+
{
696+
$betterReflectionClass = $this->createMock(BetterReflectionClass::class);
697+
$betterReflectionClass
698+
->method('getName')
699+
->willReturn('Foo');
700+
701+
$betterReflectionProperty = $this->createMock(BetterReflectionProperty::class);
702+
$betterReflectionProperty
703+
->method('getDeclaringClass')
704+
->willReturn($betterReflectionClass);
705+
$betterReflectionProperty
706+
->method('getName')
707+
->willReturn('privateProperty');
708+
$betterReflectionProperty
709+
->method('isPrivate')
710+
->willReturn(true);
711+
$betterReflectionProperty
712+
->method('isProtected')
713+
->willReturn(false);
714+
715+
$reflectionPropertyAdapter = new ReflectionPropertyAdapter($betterReflectionProperty);
716+
self::assertSame("\0Foo\0privateProperty", $reflectionPropertyAdapter->getMangledName());
717+
}
643718
}

0 commit comments

Comments
 (0)