diff --git a/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/cast_array_key_first_value.php.inc b/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/cast_array_key_first_value.php.inc new file mode 100644 index 00000000000..fc94b256434 --- /dev/null +++ b/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/cast_array_key_first_value.php.inc @@ -0,0 +1,33 @@ +stmts); + } +} + +?> +----- +stmts; + reset($stmts); + $firstItemKey = key($stmts); + } +} + +?> diff --git a/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/cast_array_key_last_value.php.inc b/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/cast_array_key_last_value.php.inc new file mode 100644 index 00000000000..427dc4f1e51 --- /dev/null +++ b/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/cast_array_key_last_value.php.inc @@ -0,0 +1,33 @@ +stmts); + } +} + +?> +----- +stmts; + end($stmts); + $lastItemKey = key($stmts); + } +} + +?> diff --git a/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/double_cast.php.inc b/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/double_cast.php.inc new file mode 100644 index 00000000000..ab6492fde73 --- /dev/null +++ b/rules-tests/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector/Fixture/double_cast.php.inc @@ -0,0 +1,33 @@ +stmts); + } +} + +?> +----- +stmts; + end($stmts); + $lastItemKey = key($stmts); + } +} + +?> diff --git a/rules/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector.php b/rules/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector.php index 630de8fe6c2..c6013639d1c 100644 --- a/rules/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector.php +++ b/rules/DowngradePhp73/Rector/FuncCall/DowngradeArrayKeyFirstLastRector.php @@ -6,9 +6,16 @@ use PhpParser\Node; use PhpParser\Node\Arg; +use PhpParser\Node\Expr; +use PhpParser\Node\Expr\Assign; +use PhpParser\Node\Expr\Cast\Array_; use PhpParser\Node\Expr\FuncCall; +use PhpParser\Node\Expr\Variable; use PhpParser\Node\Name; +use PhpParser\Node\Stmt\Expression; use Rector\Core\Rector\AbstractRector; +use Rector\Naming\Naming\VariableNaming; +use Rector\NodeTypeResolver\Node\AttributeKey; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -19,6 +26,11 @@ */ final class DowngradeArrayKeyFirstLastRector extends AbstractRector { + public function __construct( + private readonly VariableNaming $variableNaming + ) { + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition('Downgrade array_key_first() and array_key_last() functions', [ @@ -82,12 +94,20 @@ private function refactorArrayKeyFirst(FuncCall $funcCall): ?FuncCall return null; } - $array = $funcCall->args[0]->value; + $originalArray = $funcCall->args[0]->value; + $array = $this->resolveCastedArray($originalArray); + + if ($originalArray !== $array) { + $this->addAssignNewVariable($funcCall, $originalArray, $array); + } $resetFuncCall = $this->nodeFactory->createFuncCall('reset', [$array]); $this->nodesToAddCollector->addNodeBeforeNode($resetFuncCall, $funcCall); $funcCall->name = new Name('key'); + if ($originalArray !== $array) { + $funcCall->args[0]->value = $array; + } return $funcCall; } @@ -102,12 +122,45 @@ private function refactorArrayKeyLast(FuncCall $funcCall): ?FuncCall return null; } - $array = $funcCall->args[0]->value; + $originalArray = $funcCall->args[0]->value; + $array = $this->resolveCastedArray($originalArray); + + if ($originalArray !== $array) { + $this->addAssignNewVariable($funcCall, $originalArray, $array); + } + $resetFuncCall = $this->nodeFactory->createFuncCall('end', [$array]); $this->nodesToAddCollector->addNodeBeforeNode($resetFuncCall, $funcCall); $funcCall->name = new Name('key'); + if ($originalArray !== $array) { + $funcCall->args[0]->value = $array; + } return $funcCall; } + + private function addAssignNewVariable(FuncCall $funcCall, Expr $expr, Expr|Variable $variable): void + { + $this->addNodeBeforeNode(new Expression(new Assign($variable, $expr)), $funcCall); + } + + private function resolveCastedArray(Expr $expr): Expr|Variable + { + if (! $expr instanceof Array_) { + return $expr; + } + + if ($expr->expr instanceof Array_) { + return $this->resolveCastedArray($expr->expr); + } + + $scope = $expr->getAttribute(AttributeKey::SCOPE); + $variableName = $this->variableNaming->createCountedValueName( + (string) $this->nodeNameResolver->getName($expr->expr), + $scope + ); + + return new Variable($variableName); + } }