From 2707db18d96cdf280bef680ab0db6525a9d82cde Mon Sep 17 00:00:00 2001 From: Floris Luiten Date: Tue, 9 Dec 2025 13:36:55 +0100 Subject: [PATCH 1/2] Setup test for order of optional parameters In PHP, optional parameters should be declared after required parameters, otherwise they will be implicitly treated as required parameters. --- ..._default_and_without_default_value.php.inc | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 rules-tests/Symfony73/Rector/Class_/InvokableCommandInputAttributeRector/Fixture/with_default_and_without_default_value.php.inc diff --git a/rules-tests/Symfony73/Rector/Class_/InvokableCommandInputAttributeRector/Fixture/with_default_and_without_default_value.php.inc b/rules-tests/Symfony73/Rector/Class_/InvokableCommandInputAttributeRector/Fixture/with_default_and_without_default_value.php.inc new file mode 100644 index 000000000..1f0d47bd5 --- /dev/null +++ b/rules-tests/Symfony73/Rector/Class_/InvokableCommandInputAttributeRector/Fixture/with_default_and_without_default_value.php.inc @@ -0,0 +1,63 @@ +addOption('option', 'o', InputOption::VALUE_NONE, 'Option description', false); + $this->addOption('another', 'a', InputOption::VALUE_REQUIRED, 'No default value'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $someOption = $input->getOption('option'); + $another = $input->getOption('another'); + $output->writeln('Using output too'); + + // ... + + return 1; + } +} + +?> + ----- +writeln('Using output too'); + + // ... + + return 1; + } +} + +?> From 80598ebdb12568beb6b69bac300ecb2ec0118ce9 Mon Sep 17 00:00:00 2001 From: Floris Luiten Date: Tue, 9 Dec 2025 13:37:19 +0100 Subject: [PATCH 2/2] Potential fix --- .../Class_/InvokableCommandInputAttributeRector.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rules/Symfony73/Rector/Class_/InvokableCommandInputAttributeRector.php b/rules/Symfony73/Rector/Class_/InvokableCommandInputAttributeRector.php index 876c7fedb..b782fa43a 100644 --- a/rules/Symfony73/Rector/Class_/InvokableCommandInputAttributeRector.php +++ b/rules/Symfony73/Rector/Class_/InvokableCommandInputAttributeRector.php @@ -9,6 +9,7 @@ use PhpParser\Node\Expr\Variable; use PhpParser\Node\Identifier; use PhpParser\Node\Name; +use PhpParser\Node\Param; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; @@ -167,7 +168,13 @@ public function refactor(Node $node): ?Class_ $invokeParams = []; } - $executeClassMethod->params = array_merge($invokeParams, [$executeClassMethod->params[1]]); + $executeClassMethodParams = array_merge($invokeParams, [$executeClassMethod->params[1]]); + + // Ensure that optional parameters are listed last in the argument list + $executeClassMethod->params = array_merge( + array_filter($executeClassMethodParams, fn(Param $param) => is_null($param->default)), + array_filter($executeClassMethodParams, fn(Param $param) => !is_null($param->default)), + ); // 6. remove parent class $node->extends = null;