diff --git a/src/main/php/lang/reflection/Property.class.php b/src/main/php/lang/reflection/Property.class.php index 7fd2a4d..267955b 100755 --- a/src/main/php/lang/reflection/Property.class.php +++ b/src/main/php/lang/reflection/Property.class.php @@ -1,6 +1,6 @@ propertyAnnotations($this->reflect); } @@ -19,6 +24,11 @@ protected function meta() { return Reflection::meta()->propertyAnnotations($this */ public function comment() { return Reflection::meta()->propertyComment($this->reflect); } + /** Returns whether this property is virtual */ + public function virtual() { + return $this->reflect instanceof VirtualProperty || self::$HOOKS && $this->reflect->isVirtual(); + } + /** Returns a compound name consisting of `[CLASS]::$[NAME]` */ public function compoundName(): string { return strtr($this->reflect->getDeclaringClass()->name , '\\', '.').'::$'.$this->reflect->getName(); diff --git a/src/test/php/lang/reflection/unittest/PropertyHooksTest.class.php b/src/test/php/lang/reflection/unittest/PropertyHooksTest.class.php new file mode 100755 index 0000000..3c6f645 --- /dev/null +++ b/src/test/php/lang/reflection/unittest/PropertyHooksTest.class.php @@ -0,0 +1,59 @@ +declare('{ public string $fixture { get => "test"; } }'); + Assert::true($type->properties()->named('fixture')->virtual()); + } + + #[Test] + public function get() { + $type= $this->declare('{ public string $fixture { get => "test"; } }'); + $instance= $type->newInstance(); + + Assert::equals('test', $type->properties()->named('fixture')->get($instance)); + } + + #[Test] + public function set() { + $type= $this->declare('{ public string $fixture { set => ucfirst($value); } }'); + $instance= $type->newInstance(); + $type->properties()->named('fixture')->set($instance, 'test'); + + Assert::equals('Test', $instance->fixture); + } + + #[Test] + public function set_with_parameter() { + $type= $this->declare('{ public string $fixture { set(string $arg) => ucfirst($arg); } }'); + $instance= $type->newInstance(); + $type->properties()->named('fixture')->set($instance, 'test'); + + Assert::equals('Test', $instance->fixture); + } + + #[Test, Expect(AccessingFailed::class)] + public function get_set_only_raises() { + $type= $this->declare('{ public string $fixture { set => ucfirst($value); } }'); + $instance= $type->newInstance(); + + $type->properties()->named('fixture')->get($instance); + } + + #[Test, Expect(AccessingFailed::class)] + public function set_get_only_raises() { + $type= $this->declare('{ public string $fixture { get => "test"; } }'); + $instance= $type->newInstance(); + + $type->properties()->named('fixture')->set($instance, 'test'); + } +} \ No newline at end of file diff --git a/src/test/php/lang/reflection/unittest/VirtualPropertiesTest.class.php b/src/test/php/lang/reflection/unittest/VirtualPropertiesTest.class.php index 234c251..4bdc2a6 100755 --- a/src/test/php/lang/reflection/unittest/VirtualPropertiesTest.class.php +++ b/src/test/php/lang/reflection/unittest/VirtualPropertiesTest.class.php @@ -16,11 +16,7 @@ private function fixtures() { DETAIL_RETURNS => 'string', DETAIL_ARGUMENTS => [Modifiers::IS_PUBLIC | Modifiers::IS_READONLY] ]; - yield $t; - if (PHP_VERSION_ID >= 80100) { - yield $this->declare('{ public readonly string $fixture; }'); - } } #[Test, Values(from: 'fixtures')] @@ -36,6 +32,11 @@ public function virtual_property_included_in_list($type) { ); } + #[Test, Values(from: 'fixtures')] + public function is_virtual($type) { + Assert::true($type->properties()->named('fixture')->virtual()); + } + #[Test, Values(from: 'fixtures')] public function named_virtual($type) { Assert::equals($type->property('fixture'), $type->properties()->named('fixture'));