From f8ad47106a780f4b75180a1703f09ddd33f6bfbb Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Sun, 29 Jan 2023 13:27:38 +0100 Subject: [PATCH 1/2] Prefer PHP 8 attributes over xp::$meta --- src/main/php/lang/Reflection.class.php | 5 +- .../php/lang/meta/FromSyntaxTree.class.php | 73 +++++++++++++++---- .../php/lang/meta/MetaInformation.class.php | 59 +++------------ .../reflection/unittest/Fixture.class.php | 11 ++- .../unittest/MetaInformationTest.class.php | 15 +++- .../unittest/ReflectionTest.class.php | 11 --- 6 files changed, 92 insertions(+), 82 deletions(-) diff --git a/src/main/php/lang/Reflection.class.php b/src/main/php/lang/Reflection.class.php index d02f865..c354e2a 100755 --- a/src/main/php/lang/Reflection.class.php +++ b/src/main/php/lang/Reflection.class.php @@ -22,13 +22,10 @@ abstract class Reflection { private static $meta= null; - public static function annotations($version) { - return $version >= 80000 ? new FromAttributes() : new FromSyntaxTree(); - } /** Lazy-loads meta information extraction */ public static function meta(): MetaInformation { - return self::$meta ?? self::$meta= new MetaInformation(self::annotations(PHP_VERSION_ID)); + return self::$meta ?? self::$meta= new MetaInformation(); } /** diff --git a/src/main/php/lang/meta/FromSyntaxTree.class.php b/src/main/php/lang/meta/FromSyntaxTree.class.php index ba0f09d..a39e967 100755 --- a/src/main/php/lang/meta/FromSyntaxTree.class.php +++ b/src/main/php/lang/meta/FromSyntaxTree.class.php @@ -111,7 +111,7 @@ public function evaluate($reflect, $code) { * @param lang.ast.nodes.Annotated $annotated * @return [:var] */ - private function annotations($tree, $annotated) { + private function treeAnnotations($tree, $annotated) { if (null === $annotated->annotations) return []; $r= []; @@ -130,6 +130,20 @@ private function annotations($tree, $annotated) { return $r; } + /** + * Constructs annotations from meta information + * + * @param [:var] $meta + * @return [:var] + */ + private function metaAnnotations($meta) { + $r= []; + foreach ($meta[DETAIL_ANNOTATIONS] as $name => $value) { + $r[$meta[DETAIL_TARGET_ANNO][$name] ?? $name]= (array)$value; + } + return $r; + } + public function imports($reflect) { $resolver= $this->tree($reflect->name)->resolver(); $imports= []; @@ -141,35 +155,64 @@ public function imports($reflect) { /** @return iterable */ public function ofType($reflect) { - $tree= $this->tree($reflect->name); - return $this->annotations($tree, $tree->type()); + if ($meta= \xp::$meta[strtr($reflect->name, '\\', '.')]['class'] ?? null) { + return $this->metaAnnotations($meta); + } else { + $tree= $this->tree($reflect->name); + return $this->treeAnnotations($tree, $tree->type()); + } } /** @return iterable */ public function ofConstant($reflect) { - $tree= $this->tree($reflect->getDeclaringClass()->name); - return $this->annotations($tree, $tree->type()->constant($reflect->name)); + $type= $reflect->getDeclaringClass()->name; + if ($meta= \xp::$meta[strtr($type, '\\', '.')][2][$reflect->name] ?? null) { + return $this->metaAnnotations($meta); + } else { + $tree= $this->tree($type); + return $this->treeAnnotations($tree, $tree->type()->constant($reflect->name)); + } } /** @return iterable */ public function ofProperty($reflect) { - $tree= $this->tree($reflect->getDeclaringClass()->name); - return $this->annotations($tree, $tree->type()->property($reflect->name)); + $type= $reflect->getDeclaringClass()->name; + if ($meta= \xp::$meta[strtr($type, '\\', '.')][0][$reflect->name] ?? null) { + return $this->metaAnnotations($meta); + } else { + $tree= $this->tree($type); + return $this->treeAnnotations($tree, $tree->type()->property($reflect->name)); + } } /** @return iterable */ public function ofMethod($reflect) { - $tree= $this->tree($reflect->getDeclaringClass()->name); - return $this->annotations($tree, $tree->type()->method($reflect->name)); + $type= $reflect->getDeclaringClass()->name; + if ($meta= \xp::$meta[strtr($type, '\\', '.')][1][$reflect->name] ?? null) { + return $this->metaAnnotations($meta); + } else { + $tree= $this->tree($type); + return $this->treeAnnotations($tree, $tree->type()->method($reflect->name)); + } } /** @return iterable */ public function ofParameter($method, $reflect) { - $tree= $this->tree($method->getDeclaringClass()->name); - return $this->annotations($tree, $tree->type() - ->method($method->name) - ->signature - ->parameters[$reflect->getPosition()] - ); + $type= $reflect->getDeclaringClass()->name; + + if ($target= \xp::$meta[strtr($type, '\\', '.')][1][$method->name][DETAIL_TARGET_ANNO] ?? null) { + $r= []; + foreach ($target['$'.$reflect->name] ?? [] as $name => $value) { + $r[$target[$name] ?? $name]= (array)$value; + } + return $r; + } else { + $tree= $this->tree($type); + return $this->treeAnnotations($tree, $tree->type() + ->method($method->name) + ->signature + ->parameters[$reflect->getPosition()] + ); + } } } \ No newline at end of file diff --git a/src/main/php/lang/meta/MetaInformation.class.php b/src/main/php/lang/meta/MetaInformation.class.php index 887ebde..d96ec0c 100755 --- a/src/main/php/lang/meta/MetaInformation.class.php +++ b/src/main/php/lang/meta/MetaInformation.class.php @@ -9,26 +9,16 @@ class MetaInformation { private $annotations; - public function __construct($annotations) { - $this->annotations= $annotations; + public function __construct($annotations= null) { + $this->annotations= $annotations ?? self::annotations(PHP_VERSION_ID); } - public function evaluate($reflect, $code) { - return $this->annotations->evaluate($reflect, $code); + public static function annotations($version) { + return $version >= 80000 ? new FromAttributes() : new FromSyntaxTree(); } - /** - * Constructs annotations from meta information - * - * @param [:var] $meta - * @return [:var] - */ - private function annotations($meta) { - $r= []; - foreach ($meta[DETAIL_ANNOTATIONS] as $name => $value) { - $r[$meta[DETAIL_TARGET_ANNO][$name] ?? $name]= (array)$value; - } - return $r; + public function evaluate($reflect, $code) { + return $this->annotations->evaluate($reflect, $code); } /** @@ -64,11 +54,7 @@ public function scopeImports($reflect) { * @return [:var[]] */ public function typeAnnotations($reflect) { - if ($meta= \xp::$meta[strtr($reflect->name, '\\', '.')]['class'] ?? null) { - return $this->annotations($meta); - } else { - return $this->annotations->ofType($reflect); - } + return $this->annotations->ofType($reflect); } /** @@ -94,12 +80,7 @@ public function typeComment($reflect) { * @return [:var[]] */ public function constantAnnotations($reflect) { - $c= strtr($reflect->getDeclaringClass()->name, '\\', '.'); - if ($meta= \xp::$meta[$c][2][$reflect->name] ?? null) { - return $this->annotations($meta); - } else { - return $this->annotations->ofConstant($reflect); - } + return $this->annotations->ofConstant($reflect); } /** @@ -126,12 +107,7 @@ public function constantComment($reflect) { * @return [:var[]] */ public function propertyAnnotations($reflect) { - $c= strtr($reflect->getDeclaringClass()->name, '\\', '.'); - if ($meta= \xp::$meta[$c][0][$reflect->name] ?? null) { - return $this->annotations($meta); - } else { - return $this->annotations->ofProperty($reflect); - } + return $this->annotations->ofProperty($reflect); } /** @@ -174,12 +150,7 @@ public function propertyComment($reflect) { * @return [:var[]] */ public function methodAnnotations($reflect) { - $c= strtr($reflect->getDeclaringClass()->name, '\\', '.'); - if ($meta= \xp::$meta[$c][1][$reflect->name] ?? null) { - return $this->annotations($meta); - } else { - return $this->annotations->ofMethod($reflect); - } + return $this->annotations->ofMethod($reflect); } /** @@ -239,16 +210,6 @@ public function methodParameterTypes($method) { * @return [:var[]] */ public function parameterAnnotations($method, $reflect) { - $c= strtr($method->getDeclaringClass()->name, '\\', '.'); - if ($target= \xp::$meta[$c][1][$method->name][DETAIL_TARGET_ANNO] ?? null) { - if ($param= $target['$'.$reflect->name] ?? null) { - $r= []; - foreach ($param as $name => $value) { - $r[$target[$name] ?? $name]= (array)$value; - } - return $r; - } - } return $this->annotations->ofParameter($method, $reflect); } diff --git a/src/test/php/lang/reflection/unittest/Fixture.class.php b/src/test/php/lang/reflection/unittest/Fixture.class.php index 8f3203b..08b4f67 100755 --- a/src/test/php/lang/reflection/unittest/Fixture.class.php +++ b/src/test/php/lang/reflection/unittest/Fixture.class.php @@ -1,13 +1,22 @@ value= $value; } diff --git a/src/test/php/lang/reflection/unittest/MetaInformationTest.class.php b/src/test/php/lang/reflection/unittest/MetaInformationTest.class.php index eb3b1f7..66f485a 100755 --- a/src/test/php/lang/reflection/unittest/MetaInformationTest.class.php +++ b/src/test/php/lang/reflection/unittest/MetaInformationTest.class.php @@ -1,6 +1,7 @@ reflect= new \ReflectionClass(Fixture::class); + $this->reflect= new ReflectionClass(Fixture::class); } #[After] @@ -45,6 +46,16 @@ public function finalize() { unset(\xp::$meta['lang.reflection.unittest.Fixture']); } + #[Test, Values([70000, 70100, 70200, 70300, 70400])] + public function parser_for_php7($versionId) { + Assert::instance(FromSyntaxTree::class, MetaInformation::annotations($versionId)); + } + + #[Test, Values([80000, 80100, 80200, 80300])] + public function parser_for_php8($versionId) { + Assert::instance(FromAttributes::class, MetaInformation::annotations($versionId)); + } + #[Test] public function type_comment() { Assert::equals('Test', (new MetaInformation(null))->typeComment($this->reflect)); diff --git a/src/test/php/lang/reflection/unittest/ReflectionTest.class.php b/src/test/php/lang/reflection/unittest/ReflectionTest.class.php index 41d9ea8..9cb2b48 100755 --- a/src/test/php/lang/reflection/unittest/ReflectionTest.class.php +++ b/src/test/php/lang/reflection/unittest/ReflectionTest.class.php @@ -1,7 +1,6 @@ Date: Sun, 29 Jan 2023 13:32:27 +0100 Subject: [PATCH 2/2] Remove PHP 8.3 for the moment Broken on Windows for some weird reason, see https://github.com/xp-framework/reflection/actions/runs/4036764434/jobs/6939603401 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fdb50ed..4d582fb 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + php-versions: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] os: [ubuntu-latest, windows-latest] steps: