From 9d42b58a073350a18ac90050de46fb664e21f908 Mon Sep 17 00:00:00 2001 From: Pascal CESCON - Amoifr Date: Tue, 7 Apr 2026 17:05:23 +0200 Subject: [PATCH 1/2] Fix PHP 8.4 property hooks support in ClassSourceManipulator Use ParserFactory::createForHostVersion() instead of hardcoded PHP 8.1 parser to automatically detect and use the appropriate PHP version. This fixes the PhpParser\Error when parsing entities that use PHP 8.4 property hooks (e.g. private(set), get/set hooks). Fixes #1716 --- src/Util/ClassSourceManipulator.php | 10 ++----- tests/Util/ClassSourceManipulatorTest.php | 27 +++++++++++++++++++ .../fixtures/source/User_property_hooks.php | 15 +++++++++++ 3 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 tests/Util/fixtures/source/User_property_hooks.php diff --git a/src/Util/ClassSourceManipulator.php b/src/Util/ClassSourceManipulator.php index c944503dd..7d48ee63e 100644 --- a/src/Util/ClassSourceManipulator.php +++ b/src/Util/ClassSourceManipulator.php @@ -23,12 +23,11 @@ use Doctrine\ORM\Mapping\OneToOne; use PhpParser\Builder; use PhpParser\BuilderHelpers; -use PhpParser\Lexer; use PhpParser\Node; use PhpParser\NodeTraverser; use PhpParser\NodeVisitor; use PhpParser\Parser; -use PhpParser\PhpVersion; +use PhpParser\ParserFactory; use Symfony\Bundle\MakerBundle\ConsoleStyle; use Symfony\Bundle\MakerBundle\Doctrine\BaseCollectionRelation; use Symfony\Bundle\MakerBundle\Doctrine\BaseRelation; @@ -51,7 +50,6 @@ final class ClassSourceManipulator private const DEFAULT_VALUE_NONE = '__default_value_none'; private Parser $parser; - private Lexer\Emulative $lexer; private PrettyPrinter $printer; private ?ConsoleStyle $io = null; @@ -66,11 +64,7 @@ public function __construct( private bool $overwrite = false, private bool $useAttributesForDoctrineMapping = true, ) { - $this->lexer = new Lexer\Emulative( - PhpVersion::fromString('8.1'), - ); - $this->parser = new Parser\Php7($this->lexer); - + $this->parser = (new ParserFactory())->createForHostVersion(); $this->printer = new PrettyPrinter(); $this->setSourceCode($sourceCode); diff --git a/tests/Util/ClassSourceManipulatorTest.php b/tests/Util/ClassSourceManipulatorTest.php index 421078133..f1d6e5a95 100644 --- a/tests/Util/ClassSourceManipulatorTest.php +++ b/tests/Util/ClassSourceManipulatorTest.php @@ -870,4 +870,31 @@ public function testAddConstructorInClassContainsConstructor() CODE ); } + + /** + * @requires PHP >= 8.4 + */ + public function testParsingPhp84PropertyHooks(): void + { + $source = file_get_contents(__DIR__.'/fixtures/source/User_property_hooks.php'); + + // This should not throw a PhpParser\Error + $manipulator = new ClassSourceManipulator($source); + + // Verify we can still work with the class + $this->assertStringContainsString('class User', $manipulator->getSourceCode()); + } + + /** + * @requires PHP >= 8.4 + */ + public function testAddPropertyToClassWithPropertyHooks(): void + { + $source = file_get_contents(__DIR__.'/fixtures/source/User_property_hooks.php'); + + $manipulator = new ClassSourceManipulator($source); + $manipulator->addProperty(name: 'newProp', propertyType: '?string'); + + $this->assertStringContainsString('private ?string $newProp', $manipulator->getSourceCode()); + } } diff --git a/tests/Util/fixtures/source/User_property_hooks.php b/tests/Util/fixtures/source/User_property_hooks.php new file mode 100644 index 000000000..8752e3f2e --- /dev/null +++ b/tests/Util/fixtures/source/User_property_hooks.php @@ -0,0 +1,15 @@ + $this->extra ?? []; + set => $value; + } +} \ No newline at end of file From 5635b67f97a604dba921398266f7b645022c5ad1 Mon Sep 17 00:00:00 2001 From: Pascal CESCON - Amoifr Date: Wed, 8 Apr 2026 08:16:58 +0200 Subject: [PATCH 2/2] Address review feedback: add missing EOL and PHPUnit attributes --- tests/Util/ClassSourceManipulatorTest.php | 2 ++ tests/Util/fixtures/source/User_property_hooks.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Util/ClassSourceManipulatorTest.php b/tests/Util/ClassSourceManipulatorTest.php index f1d6e5a95..be9a3d5d0 100644 --- a/tests/Util/ClassSourceManipulatorTest.php +++ b/tests/Util/ClassSourceManipulatorTest.php @@ -874,6 +874,7 @@ public function testAddConstructorInClassContainsConstructor() /** * @requires PHP >= 8.4 */ + #[\PHPUnit\Framework\Attributes\RequiresPhp('>= 8.4')] public function testParsingPhp84PropertyHooks(): void { $source = file_get_contents(__DIR__.'/fixtures/source/User_property_hooks.php'); @@ -888,6 +889,7 @@ public function testParsingPhp84PropertyHooks(): void /** * @requires PHP >= 8.4 */ + #[\PHPUnit\Framework\Attributes\RequiresPhp('>= 8.4')] public function testAddPropertyToClassWithPropertyHooks(): void { $source = file_get_contents(__DIR__.'/fixtures/source/User_property_hooks.php'); diff --git a/tests/Util/fixtures/source/User_property_hooks.php b/tests/Util/fixtures/source/User_property_hooks.php index 8752e3f2e..a1c5fc37c 100644 --- a/tests/Util/fixtures/source/User_property_hooks.php +++ b/tests/Util/fixtures/source/User_property_hooks.php @@ -12,4 +12,4 @@ class User get => $this->extra ?? []; set => $value; } -} \ No newline at end of file +}