From 07c81bf7ba10dfce8963640b47de377ba4fed85e Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Wed, 22 Jul 2026 19:36:15 +0800 Subject: [PATCH] refactor(compiler): replace ExtensionProvider with MethodsFor attribute - Renamed ExtensionProvider attribute to MethodsFor across all test files - Updated keyword extension tests to use MethodsFor instead of ExtensionProvider - Modified universal method extension tests to reflect the attribute name change - Adjusted stream method extension tests to use new attribute naming - Changed object extension tests to use MethodsFor attribute - Updated constant expression validation logic for PHP 8.3+ static initializers - Added support for dynamic static variable initializers in PHP 8.3 and later - Removed --- phpunit/src/ConstantExpressionValidatorTest.php | 9 +++++++++ .../ConstantExpressionValidationVisitor.php | 10 ++++++++-- tests/compiler/attribute/003.phpt | 12 ++++++++---- tests/compiler/attribute/attributes.phpt | 7 ++----- tests/compiler/keyword_extension/001.phpt | 4 ++-- tests/compiler/keyword_extension/camel.phpt | 6 +++--- tests/compiler/stream_method/extension.phpt | 2 +- tests/compiler/trait/trait-basic.phpt | 7 ++----- .../compiler/universal_method/object_extension.phpt | 4 ++-- .../object_extension_exact_name.phpt | 4 ++-- .../universal_method/universal_method_extension.phpt | 8 ++++---- .../universal_method_extension_camel.phpt | 6 +++--- .../universal_method_extension_chain.phpt | 8 ++++---- .../universal_method/universal_method_internal.phpt | 2 +- tests/compiler/var_convert/002.phpt | 2 +- 15 files changed, 52 insertions(+), 39 deletions(-) diff --git a/phpunit/src/ConstantExpressionValidatorTest.php b/phpunit/src/ConstantExpressionValidatorTest.php index 22798945..d8db73ce 100644 --- a/phpunit/src/ConstantExpressionValidatorTest.php +++ b/phpunit/src/ConstantExpressionValidatorTest.php @@ -173,6 +173,10 @@ final class ConstantExpressionValidatorTest extends PHPUnit\Framework\TestCase yield 'parameter default allows new' => ['function f($value = new Value()) {}', '8.4']; yield 'global const allows new' => ['const VALUE = new Value();', '8.4']; yield 'static variable allows new' => ['function f() { static $value = new Value(); }', '8.4']; + yield 'PHP 8.3 static variable allows dynamic initializer' => [ + 'function f(int $seed) { static $value = loadValue($seed); }', + '8.3', + ]; yield 'PHP 8.5 class constant allows static closure' => [ 'class C { const VALUE = static function (): int { return 1; }; }', '8.5', @@ -198,6 +202,11 @@ final class ConstantExpressionValidatorTest extends PHPUnit\Framework\TestCase '8.4', 'New expressions are not supported in this context', ]; + yield 'PHP 8.2 static variable rejects dynamic initializer' => [ + 'function f(int $seed) { static $value = loadValue($seed); }', + '8.2', + 'Constant expression contains invalid operations', + ]; yield 'property rejects new' => [ 'class C { public mixed $value = new Value(); }', '8.4', diff --git a/src/Transform/ConstantExpressionValidationVisitor.php b/src/Transform/ConstantExpressionValidationVisitor.php index a59facdc..791c0e0a 100644 --- a/src/Transform/ConstantExpressionValidationVisitor.php +++ b/src/Transform/ConstantExpressionValidationVisitor.php @@ -15,15 +15,21 @@ use PhpParser\NodeVisitorAbstract; * Applies the allow_dynamic values used by php-src at each declaration site. * * false: class constants, property defaults and enum cases. - * true: attributes, parameter defaults, global constants and static variables. + * true: attributes, parameter defaults and global constants. + * + * Static variable initializers are constant expressions on PHP 8.2. PHP 8.3 + * and later compile them as regular expressions and evaluate them only once. */ final class ConstantExpressionValidationVisitor extends NodeVisitorAbstract { private readonly ConstantExpressionValidator $validator; + private readonly bool $supportsDynamicStaticInitializers; + public function __construct(string $phpVersion) { $this->validator = new ConstantExpressionValidator($phpVersion); + $this->supportsDynamicStaticInitializers = version_compare($phpVersion, '8.3', '>='); } public function enterNode(Node $node): null @@ -70,7 +76,7 @@ final class ConstantExpressionValidationVisitor extends NodeVisitorAbstract return null; } - if ($node instanceof Node\Stmt\Static_) { + if ($node instanceof Node\Stmt\Static_ && !$this->supportsDynamicStaticInitializers) { foreach ($node->vars as $variable) { if ($variable->default !== null) { $this->validator->validate($variable->default, allowDynamic: true); diff --git a/tests/compiler/attribute/003.phpt b/tests/compiler/attribute/003.phpt index 49ab0988..fb7adcc1 100644 --- a/tests/compiler/attribute/003.phpt +++ b/tests/compiler/attribute/003.phpt @@ -1,7 +1,6 @@ --TEST-- Attribute: 003 --SKIPIF-- - --FILE-- - object(ReflectionAttribute)#3 (1) { - ["name"]=> - string(11) "MyAttribute" + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) } } \ No newline at end of file diff --git a/tests/compiler/attribute/attributes.phpt b/tests/compiler/attribute/attributes.phpt index bb0c6ec2..85520c39 100644 --- a/tests/compiler/attribute/attributes.phpt +++ b/tests/compiler/attribute/attributes.phpt @@ -1,9 +1,6 @@ --TEST-- Attributes (Annotations) - PHP 8+ metadata syntax --SKIPIF-- - --FILE-- --EXPECT-- int(1) -string(11) "/api/users" +string(10) "/api/users" array(2) { [0]=> string(3) "GET" @@ -117,4 +114,4 @@ int(1) string(2) "id" string(3) "int" int(1) -string(11) "/api/posts" +string(10) "/api/posts" diff --git a/tests/compiler/keyword_extension/001.phpt b/tests/compiler/keyword_extension/001.phpt index 5227daf9..62809e03 100644 --- a/tests/compiler/keyword_extension/001.phpt +++ b/tests/compiler/keyword_extension/001.phpt @@ -1,11 +1,11 @@ --TEST-- -Keyword ExtensionProvider method with snake_case name +Keyword MethodsFor method with snake_case name --FILE-- --FILE--