diff --git a/rules-tests/DowngradePhp82/Rector/FuncCall/DowngradeIteratorCountToArrayRector/Fixture/wrap_mixed_once.php.inc b/rules-tests/DowngradePhp82/Rector/FuncCall/DowngradeIteratorCountToArrayRector/Fixture/wrap_mixed_once.php.inc new file mode 100644 index 00000000..abba1b27 --- /dev/null +++ b/rules-tests/DowngradePhp82/Rector/FuncCall/DowngradeIteratorCountToArrayRector/Fixture/wrap_mixed_once.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules/DowngradePhp82/Rector/FuncCall/DowngradeIteratorCountToArrayRector.php b/rules/DowngradePhp82/Rector/FuncCall/DowngradeIteratorCountToArrayRector.php index 8b4ee701..ccabb63d 100644 --- a/rules/DowngradePhp82/Rector/FuncCall/DowngradeIteratorCountToArrayRector.php +++ b/rules/DowngradePhp82/Rector/FuncCall/DowngradeIteratorCountToArrayRector.php @@ -6,6 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Arg; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\New_; use PhpParser\Node\Expr\Ternary; @@ -81,6 +82,12 @@ public function refactor(Node $node): null|FuncCall return null; } + // already wrapped in a previous pass; the wrap type stays not-yes-object (e.g. ArrayIterator|mixed), + // so without this check it would be wrapped again on every pass + if ($this->isArrayIteratorWrapped($arg->value)) { + return null; + } + $type = $this->nodeTypeResolver->getType($arg->value); if ($this->shouldSkip($type)) { return null; @@ -100,6 +107,23 @@ public function refactor(Node $node): null|FuncCall return $node; } + private function isArrayIteratorWrapped(Expr $expr): bool + { + if (! $expr instanceof Ternary) { + return false; + } + + if (! $expr->cond instanceof FuncCall || ! $this->isName($expr->cond, 'is_array')) { + return false; + } + + if (! $expr->if instanceof New_) { + return false; + } + + return $this->isName($expr->if->class, 'ArrayIterator'); + } + private function shouldSkip(Type $type): bool { if ($type->isArray()->yes()) {