Skip to content

Commit 6f8c0c0

Browse files
committed
feat improve preg_split type Extension
1 parent 46b9819 commit 6f8c0c0

File tree

1 file changed

+69
-4
lines changed

1 file changed

+69
-4
lines changed

src/Type/Php/PregSplitDynamicReturnTypeExtension.php

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
use PHPStan\Type\ArrayType;
1111
use PHPStan\Type\BitwiseFlagHelper;
1212
use PHPStan\Type\Constant\ConstantArrayType;
13+
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
1314
use PHPStan\Type\Constant\ConstantBooleanType;
1415
use PHPStan\Type\Constant\ConstantIntegerType;
16+
use PHPStan\Type\Constant\ConstantStringType;
1517
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
18+
use PHPStan\Type\ErrorType;
1619
use PHPStan\Type\IntegerRangeType;
1720
use PHPStan\Type\IntegerType;
1821
use PHPStan\Type\StringType;
@@ -36,17 +39,79 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo
3639

3740
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
3841
{
39-
$flagsArg = $functionCall->getArgs()[3] ?? null;
42+
$args = $functionCall->getArgs();
43+
if (count($args) < 2) {
44+
return null;
45+
}
46+
$patternArg = $args[0];
47+
$subjectArg = $args[1];
48+
$limitArg = $args[2] ?? null;
49+
$flagArg = $args[3] ?? null;
50+
$patternType = $scope->getType($patternArg->value);
51+
$patternConstantTypes = $patternType->getConstantStrings();
52+
$subjectType = $scope->getType($subjectArg->value);
53+
$subjectConstantTypes = $subjectType->getConstantStrings();
54+
55+
if (
56+
count($patternConstantTypes) > 0 &&
57+
@preg_match($patternConstantTypes[0]->getValue(), "") === false
58+
) {
59+
60+
return new ErrorType();
61+
}
4062

41-
if ($flagsArg !== null && $this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($flagsArg->value, $scope, 'PREG_SPLIT_OFFSET_CAPTURE')->yes()) {
63+
if ($subjectArg !== null && $this->bitwiseFlagAnalyser->bitwiseOrContainsConstant($subjectArg->value, $scope, 'PREG_SPLIT_OFFSET_CAPTURE')->yes()) {
4264
$type = new ArrayType(
4365
new IntegerType(),
4466
new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new StringType(), IntegerRangeType::fromInterval(0, null)], [2], [], TrinaryLogic::createYes()),
4567
);
4668
return TypeCombinator::union(TypeCombinator::intersect($type, new AccessoryArrayListType()), new ConstantBooleanType(false));
4769
}
4870

49-
return null;
50-
}
71+
if ($limitArg === null) {
72+
$limits = [-1];
73+
} else {
74+
$limitType = $scope->getType($limitArg->value);
75+
$limits = $limitType->getConstantScalarValues();
76+
}
5177

78+
if ($flagArg === null) {
79+
$flags = [0];
80+
} else {
81+
$flagType = $scope->getType($flagArg->value);
82+
$flags = $flagType->getConstantScalarValues();
83+
}
84+
85+
if (count($patternConstantTypes) === 0 || count($subjectConstantTypes) === 0 || count($flags) === 0) {
86+
return null;
87+
}
88+
89+
$resultTypes = [];
90+
foreach ($patternConstantTypes as $patternConstantType) {
91+
foreach ($subjectConstantTypes as $subjectConstantType) {
92+
foreach ($flags as $flag) {
93+
foreach ($limits as $limit) {
94+
$result = @preg_split($patternConstantType->getValue(), $subjectConstantType->getValue(), $limit, $flag);
95+
if ($result !== false) {
96+
$constantArray = ConstantArrayTypeBuilder::createEmpty();
97+
foreach ($result as $key => $value) {
98+
assert(is_int($key));
99+
if (is_array($value)) {
100+
$valueConstantArray = ConstantArrayTypeBuilder::createEmpty();
101+
$valueConstantArray->setOffsetValueType(new ConstantIntegerType(0), new ConstantStringType($value[0]));
102+
$valueConstantArray->setOffsetValueType(new ConstantIntegerType(1), new ConstantIntegerType($value[1]));
103+
$valueType = $valueConstantArray->getArray();
104+
} else {
105+
$valueType = new ConstantStringType($value);
106+
}
107+
$constantArray->setOffsetValueType(new ConstantIntegerType($key), $valueType);
108+
}
109+
$resultTypes[] = $constantArray->getArray();
110+
}
111+
}
112+
}
113+
}
114+
}
115+
return TypeCombinator::union(...$resultTypes);
116+
}
52117
}

0 commit comments

Comments
 (0)