From eaffd9c9dafe0057df114c217a3fa6681da6dd48 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 18 May 2026 11:34:08 +0200 Subject: [PATCH 1/2] kick off fix --- .../ClassDependencyManipulator.php | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/NodeManipulator/ClassDependencyManipulator.php b/src/NodeManipulator/ClassDependencyManipulator.php index 61e43fb1730..2da5a7a56e5 100644 --- a/src/NodeManipulator/ClassDependencyManipulator.php +++ b/src/NodeManipulator/ClassDependencyManipulator.php @@ -4,11 +4,13 @@ namespace Rector\NodeManipulator; +use PhpParser\Modifiers; use PhpParser\Node\Arg; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Name; +use PhpParser\Node\Param; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassLike; @@ -248,13 +250,31 @@ private function addPromotedProperty( $param = $this->nodeFactory->createPromotedPropertyParam($propertyMetadata); if ($constructClassMethod instanceof ClassMethod) { - // parameter is already added - if ($this->hasMethodParameter($constructClassMethod, $propertyMetadata->getName())) { + $hasOwnConstruct = $class->getMethod(MethodName::CONSTRUCT) instanceof ClassMethod; + $matchedParam = $this->matchMethodParameter($constructClassMethod, $propertyMetadata->getName()); + + if ($matchedParam instanceof Param) { + // own constructor already has this param → nothing to do + if ($hasOwnConstruct) { + return; + } + + // parent constructor has a same-named param; if it is a private promoted + // property, the child cannot access it via $this — add a fresh constructor + // on the child instead of trying to extend the parent signature + if (($matchedParam->flags & Modifiers::PRIVATE) !== 0) { + $childConstructClassMethod = $this->nodeFactory->createPublicMethod(MethodName::CONSTRUCT); + $childConstructClassMethod->params[] = $param; + $this->classInsertManipulator->addAsFirstMethod($class, $childConstructClassMethod); + return; + } + + // parent's matching param is protected/public — accessible from child, no add needed return; } // found construct, but only on parent, add to current class - if (! $class->getMethod(MethodName::CONSTRUCT) instanceof ClassMethod) { + if (! $hasOwnConstruct) { $parentArgs = []; foreach ($constructClassMethod->params as $originalParam) { @@ -335,14 +355,19 @@ private function hasClassPropertyAndDependency(Class_ $class, PropertyMetadata $ } private function hasMethodParameter(ClassMethod $classMethod, string $name): bool + { + return $this->matchMethodParameter($classMethod, $name) instanceof Param; + } + + private function matchMethodParameter(ClassMethod $classMethod, string $name): ?Param { foreach ($classMethod->params as $param) { if ($this->nodeNameResolver->isName($param->var, $name)) { - return true; + return $param; } } - return false; + return null; } private function shouldAddPromotedProperty(Class_ $class, PropertyMetadata $propertyMetadata): bool From 5ecb81733e481bc6e2698a3ecaacfe51145c31f1 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 18 May 2026 10:12:29 +0000 Subject: [PATCH 2/2] [ci-review] Rector Rectify --- src/NodeManipulator/ClassDependencyManipulator.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/NodeManipulator/ClassDependencyManipulator.php b/src/NodeManipulator/ClassDependencyManipulator.php index 2da5a7a56e5..9125a347977 100644 --- a/src/NodeManipulator/ClassDependencyManipulator.php +++ b/src/NodeManipulator/ClassDependencyManipulator.php @@ -354,11 +354,6 @@ private function hasClassPropertyAndDependency(Class_ $class, PropertyMetadata $ return $property instanceof Property; } - private function hasMethodParameter(ClassMethod $classMethod, string $name): bool - { - return $this->matchMethodParameter($classMethod, $name) instanceof Param; - } - private function matchMethodParameter(ClassMethod $classMethod, string $name): ?Param { foreach ($classMethod->params as $param) {