From 7fac7ed16fa723c9d43f01997d64b6a4e8f9340f Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 18 May 2024 15:32:07 +0200 Subject: [PATCH 1/2] Add support for PHP 8.4 property hooks --- .../php/lang/reflection/Property.class.php | 12 +++- .../unittest/PropertyHooksTest.class.php | 59 +++++++++++++++++++ .../unittest/VirtualPropertiesTest.class.php | 9 +-- 3 files changed, 75 insertions(+), 5 deletions(-) create mode 100755 src/test/php/lang/reflection/unittest/PropertyHooksTest.class.php 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')); From b5787e0eca6ce0c10e2b4ed5f5a994b2c89851e6 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sat, 18 May 2024 15:55:38 +0200 Subject: [PATCH 2/2] Assert backed properties are not returned as virtual See https://github.com/php/php-src/blob/c820d9ed9b7881672f38475ec16baafef518272f/Zend/tests/property_hooks/find_property_usage.phpt --- .../lang/reflection/unittest/PropertyHooksTest.class.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/php/lang/reflection/unittest/PropertyHooksTest.class.php b/src/test/php/lang/reflection/unittest/PropertyHooksTest.class.php index 3c6f645..c27892d 100755 --- a/src/test/php/lang/reflection/unittest/PropertyHooksTest.class.php +++ b/src/test/php/lang/reflection/unittest/PropertyHooksTest.class.php @@ -3,7 +3,7 @@ use ReflectionProperty; use lang\reflection\AccessingFailed; use test\verify\Condition; -use test\{Assert, Expect, Test}; +use test\{Assert, Expect, Test, Values}; #[Condition(assert: 'method_exists(ReflectionProperty::class, "getHooks")')] class PropertyHooksTest { @@ -15,6 +15,12 @@ public function is_virtual() { Assert::true($type->properties()->named('fixture')->virtual()); } + #[Test, Values(['get { return $this->fixture; }', 'get => $this->fixture;'])] + public function backed_is_not_virtual($declaration) { + $type= $this->declare('{ public string $fixture { '.$declaration.' } }'); + Assert::false($type->properties()->named('fixture')->virtual()); + } + #[Test] public function get() { $type= $this->declare('{ public string $fixture { get => "test"; } }');