Skip to content

Commit 40393c5

Browse files
authored
[Php84] Handle key used on conditional on ForeachToArray* rules (#7035)
* [Php84] Handle key used on conditional on ForeachToArray* rules * more fixtures
1 parent fe687bf commit 40393c5

10 files changed

Lines changed: 234 additions & 18 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php84\Rector\Foreach_\ForeachToArrayAllRector\Fixture;
4+
5+
class WithKey
6+
{
7+
public function run(array $animals, array $params)
8+
{
9+
$match = true;
10+
foreach ($animals as $k => $v) {
11+
if (!isset($params[$k]) || (string) $params[$k] !== (string) $v) {
12+
$match = false;
13+
break;
14+
}
15+
}
16+
return $match;
17+
}
18+
}
19+
20+
?>
21+
-----
22+
<?php
23+
24+
namespace Rector\Tests\Php84\Rector\Foreach_\ForeachToArrayAllRector\Fixture;
25+
26+
class WithKey
27+
{
28+
public function run(array $animals, array $params)
29+
{
30+
$match = array_all($animals, fn($v, $k) => !(!isset($params[$k]) || (string) $params[$k] !== (string) $v));
31+
return $match;
32+
}
33+
}
34+
35+
?>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php84\Rector\Foreach_\ForeachToArrayAnyRector\Fixture;
4+
5+
class WithKey
6+
{
7+
public function checkAnimal(array $animals)
8+
{
9+
$found = false;
10+
foreach ($animals as $key => $animal) {
11+
if (str_starts_with($animal, 'c') && $key === 1) {
12+
$found = true;
13+
break;
14+
}
15+
}
16+
return $found;
17+
}
18+
}
19+
20+
?>
21+
-----
22+
<?php
23+
24+
namespace Rector\Tests\Php84\Rector\Foreach_\ForeachToArrayAnyRector\Fixture;
25+
26+
class WithKey
27+
{
28+
public function checkAnimal(array $animals)
29+
{
30+
$found = array_any($animals, fn($animal, $key) => str_starts_with($animal, 'c') && $key === 1);
31+
return $found;
32+
}
33+
}
34+
35+
?>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php84\Rector\Foreach_\ForeachToArrayFindKeyRector\Fixture;
4+
5+
class WithKey
6+
{
7+
public function findAnimalKey(array $animals)
8+
{
9+
$found = null;
10+
foreach ($animals as $idx => $animal) {
11+
if (str_starts_with($animal, 'c') && $idx === 1) {
12+
$found = $idx;
13+
break;
14+
}
15+
}
16+
return $found;
17+
}
18+
}
19+
20+
?>
21+
-----
22+
<?php
23+
24+
namespace Rector\Tests\Php84\Rector\Foreach_\ForeachToArrayFindKeyRector\Fixture;
25+
26+
class WithKey
27+
{
28+
public function findAnimalKey(array $animals)
29+
{
30+
$found = array_find_key($animals, fn($animal, $idx) => str_starts_with($animal, 'c') && $idx === 1);
31+
return $found;
32+
}
33+
}
34+
35+
?>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php84\Rector\Foreach_\ForeachToArrayFindRector\Fixture;
4+
5+
class WithKey
6+
{
7+
public function findAnimal(array $animals)
8+
{
9+
$found = null;
10+
foreach ($animals as $key => $animal) {
11+
if (str_starts_with($animal, 'c') && $key === 1) {
12+
$found = $animal;
13+
break;
14+
}
15+
}
16+
return $found;
17+
}
18+
}
19+
20+
?>
21+
-----
22+
<?php
23+
24+
namespace Rector\Tests\Php84\Rector\Foreach_\ForeachToArrayFindRector\Fixture;
25+
26+
class WithKey
27+
{
28+
public function findAnimal(array $animals)
29+
{
30+
$found = array_find($animals, fn($animal, $key) => str_starts_with($animal, 'c') && $key === 1);
31+
return $found;
32+
}
33+
}
34+
35+
?>

rules/CodeQuality/Rector/ClassMethod/OptionalParametersAfterRequiredRector.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,8 @@ public function refactor(Node $node): ClassMethod|Function_|null|New_|MethodCall
100100
return $this->refactorMethodCallOrFuncCall($node);
101101
}
102102

103-
private function refactorClassMethodOrFunction(
104-
ClassMethod|Function_ $node
105-
): ClassMethod|Function_|null {
103+
private function refactorClassMethodOrFunction(ClassMethod|Function_ $node): ClassMethod|Function_|null
104+
{
106105
if ($node->params === []) {
107106
return null;
108107
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Php84\NodeAnalyzer;
6+
7+
use PhpParser\Node\Expr;
8+
use PhpParser\Node\Expr\Variable;
9+
use Rector\NodeNameResolver\NodeNameResolver;
10+
use Rector\PhpParser\Node\BetterNodeFinder;
11+
12+
final readonly class ForeachKeyUsedInConditionalAnalyzer
13+
{
14+
public function __construct(
15+
private BetterNodeFinder $betterNodeFinder,
16+
private NodeNameResolver $nodeNameResolver
17+
) {
18+
}
19+
20+
public function isUsed(Variable $variable, Expr $expr): bool
21+
{
22+
$keyVarName = (string) $this->nodeNameResolver->getName($variable);
23+
return (bool) $this->betterNodeFinder->findVariableOfName($expr, $keyVarName);
24+
}
25+
}

rules/Php84/Rector/Foreach_/ForeachToArrayAllRector.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use PhpParser\Node\Stmt\If_;
1717
use Rector\Contract\PhpParser\Node\StmtsAwareInterface;
1818
use Rector\NodeManipulator\StmtsManipulator;
19+
use Rector\Php84\NodeAnalyzer\ForeachKeyUsedInConditionalAnalyzer;
1920
use Rector\PhpParser\Node\Value\ValueResolver;
2021
use Rector\Rector\AbstractRector;
2122
use Rector\ValueObject\PhpVersionFeature;
@@ -30,7 +31,8 @@ final class ForeachToArrayAllRector extends AbstractRector implements MinPhpVers
3031
{
3132
public function __construct(
3233
private readonly ValueResolver $valueResolver,
33-
private readonly StmtsManipulator $stmtsManipulator
34+
private readonly StmtsManipulator $stmtsManipulator,
35+
private readonly ForeachKeyUsedInConditionalAnalyzer $foreachKeyUsedInConditionalAnalyzer
3436
) {
3537
}
3638

@@ -106,7 +108,11 @@ public function refactor(Node $node): ?Node
106108
continue;
107109
}
108110

109-
if ($this->stmtsManipulator->isVariableUsedInNextStmt($node, $key + 1, (string) $this->getName($foreach->valueVar))) {
111+
if ($this->stmtsManipulator->isVariableUsedInNextStmt(
112+
$node,
113+
$key + 1,
114+
(string) $this->getName($foreach->valueVar)
115+
)) {
110116
continue;
111117
}
112118

@@ -120,12 +126,19 @@ public function refactor(Node $node): ?Node
120126
continue;
121127
}
122128

123-
$param = new Param($valueParam);
129+
$params = [new Param($valueParam)];
130+
131+
if ($foreach->keyVar instanceof Variable && $this->foreachKeyUsedInConditionalAnalyzer->isUsed(
132+
$foreach->keyVar,
133+
$condition
134+
)) {
135+
$params[] = new Param(new Variable((string) $this->getName($foreach->keyVar)));
136+
}
124137

125138
$negatedCondition = $condition instanceof BooleanNot ? $condition->expr : new BooleanNot($condition);
126139

127140
$arrowFunction = new ArrowFunction([
128-
'params' => [$param],
141+
'params' => $params,
129142
'expr' => $negatedCondition,
130143
]);
131144

rules/Php84/Rector/Foreach_/ForeachToArrayAnyRector.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PhpParser\Node\Stmt\If_;
1616
use Rector\Contract\PhpParser\Node\StmtsAwareInterface;
1717
use Rector\NodeManipulator\StmtsManipulator;
18+
use Rector\Php84\NodeAnalyzer\ForeachKeyUsedInConditionalAnalyzer;
1819
use Rector\PhpParser\Node\Value\ValueResolver;
1920
use Rector\Rector\AbstractRector;
2021
use Rector\ValueObject\PhpVersionFeature;
@@ -29,7 +30,8 @@ final class ForeachToArrayAnyRector extends AbstractRector implements MinPhpVers
2930
{
3031
public function __construct(
3132
private readonly ValueResolver $valueResolver,
32-
private readonly StmtsManipulator $stmtsManipulator
33+
private readonly StmtsManipulator $stmtsManipulator,
34+
private readonly ForeachKeyUsedInConditionalAnalyzer $foreachKeyUsedInConditionalAnalyzer
3335
) {
3436
}
3537

@@ -105,7 +107,11 @@ public function refactor(Node $node): ?Node
105107
continue;
106108
}
107109

108-
if ($this->stmtsManipulator->isVariableUsedInNextStmt($node, $key + 1, (string) $this->getName($foreach->valueVar))) {
110+
if ($this->stmtsManipulator->isVariableUsedInNextStmt(
111+
$node,
112+
$key + 1,
113+
(string) $this->getName($foreach->valueVar)
114+
)) {
109115
continue;
110116
}
111117

@@ -119,10 +125,17 @@ public function refactor(Node $node): ?Node
119125
continue;
120126
}
121127

122-
$param = new Param($valueParam);
128+
$params = [new Param($valueParam)];
129+
130+
if ($foreach->keyVar instanceof Variable && $this->foreachKeyUsedInConditionalAnalyzer->isUsed(
131+
$foreach->keyVar,
132+
$condition
133+
)) {
134+
$params[] = new Param(new Variable((string) $this->getName($foreach->keyVar)));
135+
}
123136

124137
$arrowFunction = new ArrowFunction([
125-
'params' => [$param],
138+
'params' => $params,
126139
'expr' => $condition,
127140
]);
128141

rules/Php84/Rector/Foreach_/ForeachToArrayFindKeyRector.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use PhpParser\Node\Stmt\If_;
1717
use Rector\Contract\PhpParser\Node\StmtsAwareInterface;
1818
use Rector\NodeManipulator\StmtsManipulator;
19+
use Rector\Php84\NodeAnalyzer\ForeachKeyUsedInConditionalAnalyzer;
1920
use Rector\PhpParser\Node\Value\ValueResolver;
2021
use Rector\Rector\AbstractRector;
2122
use Rector\ValueObject\PhpVersionFeature;
@@ -31,6 +32,7 @@ final class ForeachToArrayFindKeyRector extends AbstractRector implements MinPhp
3132
public function __construct(
3233
private readonly ValueResolver $valueResolver,
3334
private readonly StmtsManipulator $stmtsManipulator,
35+
private readonly ForeachKeyUsedInConditionalAnalyzer $foreachKeyUsedInConditionalAnalyzer
3436
) {
3537
}
3638

@@ -110,7 +112,11 @@ public function refactor(Node $node): ?Node
110112
continue;
111113
}
112114

113-
if ($this->stmtsManipulator->isVariableUsedInNextStmt($node, $key + 1, (string) $this->getName($foreach->valueVar))) {
115+
if ($this->stmtsManipulator->isVariableUsedInNextStmt(
116+
$node,
117+
$key + 1,
118+
(string) $this->getName($foreach->valueVar)
119+
)) {
114120
continue;
115121
}
116122

@@ -124,10 +130,17 @@ public function refactor(Node $node): ?Node
124130
continue;
125131
}
126132

127-
$param = new Param($valueParam);
133+
$params = [new Param($valueParam)];
134+
135+
if ($foreach->keyVar instanceof Variable && $this->foreachKeyUsedInConditionalAnalyzer->isUsed(
136+
$foreach->keyVar,
137+
$condition
138+
)) {
139+
$params[] = new Param(new Variable((string) $this->getName($foreach->keyVar)));
140+
}
128141

129142
$arrowFunction = new ArrowFunction([
130-
'params' => [$param],
143+
'params' => $params,
131144
'expr' => $condition,
132145
]);
133146

rules/Php84/Rector/Foreach_/ForeachToArrayFindRector.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PhpParser\Node\Stmt\If_;
1616
use Rector\Contract\PhpParser\Node\StmtsAwareInterface;
1717
use Rector\NodeManipulator\StmtsManipulator;
18+
use Rector\Php84\NodeAnalyzer\ForeachKeyUsedInConditionalAnalyzer;
1819
use Rector\PhpParser\Node\Value\ValueResolver;
1920
use Rector\Rector\AbstractRector;
2021
use Rector\ValueObject\PhpVersionFeature;
@@ -29,7 +30,8 @@ final class ForeachToArrayFindRector extends AbstractRector implements MinPhpVer
2930
{
3031
public function __construct(
3132
private readonly ValueResolver $valueResolver,
32-
private readonly StmtsManipulator $stmtsManipulator
33+
private readonly StmtsManipulator $stmtsManipulator,
34+
private readonly ForeachKeyUsedInConditionalAnalyzer $foreachKeyUsedInConditionalAnalyzer
3335
) {
3436
}
3537

@@ -105,7 +107,11 @@ public function refactor(Node $node): ?Node
105107
continue;
106108
}
107109

108-
if ($this->stmtsManipulator->isVariableUsedInNextStmt($node, $key + 1, (string) $this->getName($foreach->valueVar))) {
110+
if ($this->stmtsManipulator->isVariableUsedInNextStmt(
111+
$node,
112+
$key + 1,
113+
(string) $this->getName($foreach->valueVar)
114+
)) {
109115
continue;
110116
}
111117

@@ -119,10 +125,17 @@ public function refactor(Node $node): ?Node
119125
continue;
120126
}
121127

122-
$param = new Param($valueParam);
128+
$params = [new Param($valueParam)];
129+
130+
if ($foreach->keyVar instanceof Variable && $this->foreachKeyUsedInConditionalAnalyzer->isUsed(
131+
$foreach->keyVar,
132+
$condition
133+
)) {
134+
$params[] = new Param(new Variable((string) $this->getName($foreach->keyVar)));
135+
}
123136

124137
$arrowFunction = new ArrowFunction([
125-
'params' => [$param],
138+
'params' => $params,
126139
'expr' => $condition,
127140
]);
128141

0 commit comments

Comments
 (0)