Skip to content

Commit

Permalink
Merge pull request #1471 from kukulich/hooks
Browse files Browse the repository at this point in the history
Support of `__PROPERTY__`
  • Loading branch information
Ocramius authored Dec 20, 2024
2 parents e037ec8 + 22cc47d commit 4241b21
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 5 deletions.
11 changes: 11 additions & 0 deletions src/NodeCompiler/CompileNodeToValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Roave\BetterReflection\Reflection\ReflectionClass;
use Roave\BetterReflection\Reflection\ReflectionClassConstant;
use Roave\BetterReflection\Reflection\ReflectionEnum;
use Roave\BetterReflection\Reflection\ReflectionMethod;
use Roave\BetterReflection\Reflector\Exception\IdentifierNotFound;
use Roave\BetterReflection\Util\FileHelper;

Expand Down Expand Up @@ -82,6 +83,16 @@ public function __invoke(Node $node, CompilerContext $context): CompiledValue
return $context->getNamespace() ?? '';
}

if ($node instanceof Node\Scalar\MagicConst\Property) {
$method = $context->getFunction();

if ($method !== null && $method instanceof ReflectionMethod && $method->isHook()) {
return $method->getHookProperty()->getName();
}

return '';
}

if ($node instanceof Node\Scalar\MagicConst\Method) {
$class = $context->getClass();
$function = $context->getFunction();
Expand Down
14 changes: 14 additions & 0 deletions src/Reflection/ReflectionMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ private function __construct(
private ReflectionClass $implementingClass,
private ReflectionClass $currentClass,
private string|null $aliasName,
private ReflectionProperty|null $hookProperty = null,
) {
assert($node instanceof MethodNode || $node instanceof Node\PropertyHook);

Expand Down Expand Up @@ -100,6 +101,7 @@ public static function createFromPropertyHook(
ReflectionClass $declaringClass,
ReflectionClass $implementingClass,
ReflectionClass $currentClass,
ReflectionProperty $hookProperty,
): self {
$method = new self(
$reflector,
Expand All @@ -111,6 +113,7 @@ public static function createFromPropertyHook(
$implementingClass,
$currentClass,
null,
$hookProperty,
);

if ($node->name->name === 'set') {
Expand Down Expand Up @@ -446,6 +449,17 @@ public function getClosure(object|null $object = null): Closure
return fn (mixed ...$args): mixed => $this->callObjectMethod($instance, $args);
}

/** @psalm-assert-if-true !null $this->getHookProperty() */
public function isHook(): bool
{
return $this->hookProperty !== null;
}

public function getHookProperty(): ReflectionProperty|null
{
return $this->hookProperty;
}

/**
* @throws ClassDoesNotExist
* @throws NoObjectProvided
Expand Down
1 change: 1 addition & 0 deletions src/Reflection/ReflectionProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ private function createImmediateHooks(PropertyNode $node): array
$this->getDeclaringClass(),
$this->getImplementingClass(),
$this->getDeclaringClass(),
$this,
);
}

Expand Down
6 changes: 6 additions & 0 deletions test/unit/Fixture/MagicConstants.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
define('_TRAIT', __TRAIT__);
define('_METHOD', __METHOD__);
define('_FUNCTION', __FUNCTION__);
define('_PROPERTY', __PROPERTY__);

}

Expand All @@ -23,6 +24,7 @@
const _TRAIT = __TRAIT__;
const _METHOD = __METHOD__;
const _FUNCTION = __FUNCTION__;
const _PROPERTY = __PROPERTY__;

trait MagicConstantsTrait
{
Expand All @@ -34,6 +36,7 @@ trait MagicConstantsTrait
protected $trait = __TRAIT__;
protected $method = __METHOD__;
protected $function = __FUNCTION__;
protected $property = __PROPERTY__;
}

class MagicConstantsClass
Expand All @@ -46,6 +49,7 @@ class MagicConstantsClass
private $trait = __TRAIT__;
private $method = __METHOD__;
private $function = __FUNCTION__;
private $property = __PROPERTY__;

public function magicConstantsMethod(
$dir = __DIR__,
Expand All @@ -56,6 +60,7 @@ public function magicConstantsMethod(
$trait = __TRAIT__,
$method = __METHOD__,
$function = __FUNCTION__,
$property = __PROPERTY__,
)
{
}
Expand All @@ -70,6 +75,7 @@ function magicConstantsFunction(
$trait = __TRAIT__,
$method = __METHOD__,
$function = __FUNCTION__,
$property = __PROPERTY__,
)
{
}
Expand Down
33 changes: 33 additions & 0 deletions test/unit/Fixture/MagicConstantsInPropertyHooks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Roave\BetterReflectionTest\Fixture;

class MagicConstantsInPropertyHooks
{
public string $propertyMagicConstantMethod {
set (
#[SomeAttribute(__METHOD__)]
string $value
) {
$this->propertyMagicConstantMethod = $value;
}
}

public string $propertyMagicConstantFunction {
set (
#[SomeAttribute(__FUNCTION__)]
string $value
) {
$this->propertyMagicConstantFunction = $value;
}
}

public string $propertyMagicConstantProperty {
set (
#[SomeAttribute(__PROPERTY__)]
string $value
) {
$this->propertyMagicConstantProperty = $value;
}
}
}
42 changes: 37 additions & 5 deletions test/unit/NodeCompiler/CompileNodeToValueTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Roave\BetterReflection\NodeCompiler\CompilerContext;
use Roave\BetterReflection\NodeCompiler\Exception\UnableToCompileNode;
use Roave\BetterReflection\Reflection\Reflection;
use Roave\BetterReflection\Reflection\ReflectionPropertyHookType;
use Roave\BetterReflection\Reflector\DefaultReflector;
use Roave\BetterReflection\Reflector\Reflector;
use Roave\BetterReflection\SourceLocator\Ast\Locator;
Expand All @@ -33,6 +34,7 @@
use Roave\BetterReflectionTest\BetterReflectionSingleton;
use Roave\BetterReflectionTest\Fixture\ClassWithNewInInitializers;
use Roave\BetterReflectionTest\Fixture\MagicConstantsClass;
use Roave\BetterReflectionTest\Fixture\MagicConstantsInPropertyHooks;
use Roave\BetterReflectionTest\Fixture\MagicConstantsTrait;

use function assert;
Expand Down Expand Up @@ -801,6 +803,7 @@ public static function magicConstantsWithoutNamespaceProvider(): array
['_TRAIT', ''],
['_METHOD', ''],
['_FUNCTION', ''],
['_PROPERTY', ''],
];
}

Expand All @@ -821,12 +824,13 @@ public static function magicConstantsInNamespaceProvider(): array
return [
['_DIR', $dir],
['_FILE', $dir . '/MagicConstants.php'],
['_LINE', 20],
['_LINE', 21],
['_NAMESPACE', 'Roave\BetterReflectionTest\Fixture'],
['_CLASS', ''],
['_TRAIT', ''],
['_METHOD', ''],
['_FUNCTION', ''],
['_PROPERTY', ''],
];
}

Expand Down Expand Up @@ -944,12 +948,13 @@ public static function magicConstantsInTraitProvider(): array
return [
['dir', $dir],
['file', $dir . '/MagicConstants.php'],
['line', 31],
['line', 33],
['namespace', 'Roave\BetterReflectionTest\Fixture'],
['class', 'Roave\BetterReflectionTest\Fixture\MagicConstantsTrait'],
['trait', 'Roave\BetterReflectionTest\Fixture\MagicConstantsTrait'],
['method', ''],
['function', ''],
['property', ''],
];
}

Expand All @@ -972,12 +977,13 @@ public static function magicConstantsInClassProvider(): array
return [
['dir', $dir],
['file', $dir . '/MagicConstants.php'],
['line', 43],
['line', 46],
['namespace', 'Roave\BetterReflectionTest\Fixture'],
['class', 'Roave\BetterReflectionTest\Fixture\MagicConstantsClass'],
['trait', ''],
['method', ''],
['function', ''],
['property', ''],
];
}

Expand All @@ -1000,12 +1006,13 @@ public static function magicConstantsInMethodProvider(): array
return [
['dir', $dir],
['file', $dir . '/MagicConstants.php'],
['line', 53],
['line', 57],
['namespace', 'Roave\BetterReflectionTest\Fixture'],
['class', 'Roave\BetterReflectionTest\Fixture\MagicConstantsClass'],
['trait', ''],
['method', 'Roave\BetterReflectionTest\Fixture\MagicConstantsClass::magicConstantsMethod'],
['function', 'magicConstantsMethod'],
['property', ''],
];
}

Expand All @@ -1029,12 +1036,13 @@ public static function magicConstantsInFunctionProvider(): array
return [
['dir', $dir],
['file', $dir . '/MagicConstants.php'],
['line', 67],
['line', 72],
['namespace', 'Roave\BetterReflectionTest\Fixture'],
['class', ''],
['trait', ''],
['method', 'Roave\BetterReflectionTest\Fixture\magicConstantsFunction'],
['function', 'Roave\BetterReflectionTest\Fixture\magicConstantsFunction'],
['property', ''],
];
}

Expand Down Expand Up @@ -1092,6 +1100,30 @@ public function testThrowExceptionWhenValueContainsInitializer(): void
$parameter->getDefaultValue();
}

/** @return list<array{0: non-empty-string, 1: mixed}> */
public static function magicConstantsInPropertyHooks(): array
{
return [
['propertyMagicConstantMethod', 'Roave\BetterReflectionTest\Fixture\MagicConstantsInPropertyHooks::$propertyMagicConstantMethod::set'],
['propertyMagicConstantFunction', '$propertyMagicConstantFunction::set'],
['propertyMagicConstantProperty', 'propertyMagicConstantProperty'],
];
}

/** @param non-empty-string $propertyName */
#[DataProvider('magicConstantsInPropertyHooks')]
public function testMagicConstantsInPropertyHooks(string $propertyName, mixed $expectedValue): void
{
$reflector = new DefaultReflector(new SingleFileSourceLocator(self::realPath(__DIR__ . '/../Fixture/MagicConstantsInPropertyHooks.php'), $this->astLocator));
$class = $reflector->reflectClass(MagicConstantsInPropertyHooks::class);
$property = $class->getProperty($propertyName);
$getHook = $property->getHook(ReflectionPropertyHookType::Set);
$getHookParameter = $getHook->getParameters()[0];
$getHookParameterAttribute = $getHookParameter->getAttributes()[0];

self::assertSame($expectedValue, $getHookParameterAttribute->getArguments()[0]);
}

/** @return non-empty-string */
private static function realPath(string|false $path): string
{
Expand Down
4 changes: 4 additions & 0 deletions test/unit/Reflection/ReflectionMethodTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,8 @@ public function testSetPropertyHookHasImplicitParameter(): void
self::assertTrue($hookProperty->hasHook(ReflectionPropertyHookType::Set));

$hookReflection = $hookProperty->getHook(ReflectionPropertyHookType::Set);
self::assertTrue($hookReflection->isHook());
self::assertSame($hookProperty, $hookReflection->getHookProperty());
self::assertInstanceOf(ReflectionType::class, $hookReflection->getReturnType());
self::assertSame('void', $hookReflection->getReturnType()->getName());

Expand All @@ -843,6 +845,8 @@ public function testSetPropertyHookHasExplicitParameter(): void
self::assertTrue($hookProperty->hasHook(ReflectionPropertyHookType::Set));

$hookReflection = $hookProperty->getHook(ReflectionPropertyHookType::Set);
self::assertTrue($hookReflection->isHook());
self::assertSame($hookProperty, $hookReflection->getHookProperty());
self::assertInstanceOf(ReflectionType::class, $hookReflection->getReturnType());
self::assertSame('void', $hookReflection->getReturnType()->getName());

Expand Down

0 comments on commit 4241b21

Please sign in to comment.