Skip to content

Commit c238fe7

Browse files
committed
Optimize match expression with many conditions
1 parent 4591b1e commit c238fe7

File tree

3 files changed

+45
-17
lines changed

3 files changed

+45
-17
lines changed

src/Analyser/MutatingScope.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,16 +1490,21 @@ private function resolveType(string $exprString, Expr $node): Type
14901490
throw new ShouldNotHappenException();
14911491
}
14921492

1493-
$filteringExpr = null;
1494-
foreach ($arm->conds as $armCond) {
1495-
$armCondExpr = new BinaryOp\Identical($cond, $armCond);
1496-
1497-
if ($filteringExpr === null) {
1498-
$filteringExpr = $armCondExpr;
1499-
continue;
1493+
if (count($arm->conds) === 1) {
1494+
$filteringExpr = new BinaryOp\Identical($cond, $arm->conds[0]);
1495+
} else {
1496+
$items = [];
1497+
foreach ($arm->conds as $filteringExpr) {
1498+
$items[] = new Expr\ArrayItem($filteringExpr);
15001499
}
1501-
1502-
$filteringExpr = new BinaryOp\BooleanOr($filteringExpr, $armCondExpr);
1500+
$filteringExpr = new FuncCall(
1501+
new Name\FullyQualified('in_array'),
1502+
[
1503+
new Arg($cond),
1504+
new Arg(new Array_($items)),
1505+
new Arg(new ConstFetch(new Name\FullyQualified('true'))),
1506+
],
1507+
);
15031508
}
15041509

15051510
$filteringExprType = $matchScope->getType($filteringExpr);

src/Analyser/NodeScopeResolver.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,7 +2849,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
28492849
throw new ShouldNotHappenException();
28502850
}
28512851

2852-
$filteringExpr = null;
2852+
$filteringExprs = [];
28532853
$armCondScope = $matchScope;
28542854
$condNodes = [];
28552855
foreach ($arm->conds as $armCond) {
@@ -2864,12 +2864,24 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
28642864
$hasAlwaysTrueCond = true;
28652865
}
28662866
$armCondScope = $armCondResult->getScope()->filterByFalseyValue($armCondExpr);
2867-
if ($filteringExpr === null) {
2868-
$filteringExpr = $armCondExpr;
2869-
continue;
2870-
}
2867+
$filteringExprs[] = $armCond;
2868+
}
28712869

2872-
$filteringExpr = new BinaryOp\BooleanOr($filteringExpr, $armCondExpr);
2870+
if (count($filteringExprs) === 1) {
2871+
$filteringExpr = new BinaryOp\Identical($expr->cond, $filteringExprs[0]);
2872+
} else {
2873+
$items = [];
2874+
foreach ($filteringExprs as $filteringExpr) {
2875+
$items[] = new ArrayItem($filteringExpr);
2876+
}
2877+
$filteringExpr = new FuncCall(
2878+
new Name\FullyQualified('in_array'),
2879+
[
2880+
new Arg($expr->cond),
2881+
new Arg(new Array_($items)),
2882+
new Arg(new ConstFetch(new Name\FullyQualified('true'))),
2883+
],
2884+
);
28732885
}
28742886

28752887
$bodyScope = $matchScope->filterByTruthyValue($filteringExpr);

src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\Analyser\TypeSpecifier;
99
use PHPStan\Analyser\TypeSpecifierAwareExtension;
1010
use PHPStan\Analyser\TypeSpecifierContext;
11+
use PHPStan\Node\Expr\AlwaysRememberedExpr;
1112
use PHPStan\Reflection\FunctionReflection;
1213
use PHPStan\Type\Accessory\NonEmptyArrayType;
1314
use PHPStan\Type\ArrayType;
@@ -47,7 +48,8 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
4748
return new SpecifiedTypes();
4849
}
4950

50-
$needleType = $scope->getType($node->getArgs()[0]->value);
51+
$needleExpr = $node->getArgs()[0]->value;
52+
$needleType = $scope->getType($needleExpr);
5153
$arrayType = $scope->getType($node->getArgs()[1]->value);
5254
$arrayValueType = $arrayType->getIterableValueType();
5355
$isStrictComparison = $isStrictComparison
@@ -71,12 +73,21 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
7173
)
7274
) {
7375
$specifiedTypes = $this->typeSpecifier->create(
74-
$node->getArgs()[0]->value,
76+
$needleExpr,
7577
$arrayValueType,
7678
$context,
7779
false,
7880
$scope,
7981
);
82+
if ($needleExpr instanceof AlwaysRememberedExpr) {
83+
$specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create(
84+
$needleExpr->getExpr(),
85+
$arrayValueType,
86+
$context,
87+
false,
88+
$scope,
89+
));
90+
}
8091
}
8192

8293
if (

0 commit comments

Comments
 (0)