Skip to content

Commit ac73701

Browse files
Rework extension
1 parent a74b5f9 commit ac73701

File tree

4 files changed

+39
-15
lines changed

4 files changed

+39
-15
lines changed

src/Type/Php/StrSplitFunctionReturnTypeExtension.php

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
5757
if ($splitLengthType instanceof ConstantIntegerType) {
5858
$splitLength = $splitLengthType->getValue();
5959
if ($splitLength < 1) {
60-
return new ConstantBooleanType(false);
60+
return $this->phpVersion->throwsValueErrorForInternalFunctions() ? null : new ConstantBooleanType(false);
6161
}
6262
}
6363
} else {
@@ -70,21 +70,19 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
7070
$strings = $scope->getType($functionCall->getArgs()[2]->value)->getConstantStrings();
7171
$values = array_unique(array_map(static fn (ConstantStringType $encoding): string => $encoding->getValue(), $strings));
7272

73-
if (count($values) !== 1) {
74-
return null;
75-
}
76-
77-
$encoding = $values[0];
78-
if (!$this->isSupportedEncoding($encoding)) {
79-
return new ConstantBooleanType(false);
73+
if (count($values) === 1) {
74+
$encoding = $values[0];
75+
if (!$this->isSupportedEncoding($encoding)) {
76+
return $this->phpVersion->throwsValueErrorForInternalFunctions() ? null : new ConstantBooleanType(false);
77+
}
8078
}
8179
} else {
8280
$encoding = mb_internal_encoding();
8381
}
8482
}
8583

8684
$stringType = $scope->getType($functionCall->getArgs()[0]->value);
87-
if (isset($splitLength)) {
85+
if (isset($splitLength) && ($functionReflection->getName() === 'str_split' || null !== $encoding)) {
8886
$constantStrings = $stringType->getConstantStrings();
8987
if (count($constantStrings) > 0) {
9088
$results = [];
@@ -118,10 +116,14 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
118116
$returnValueType = TypeCombinator::intersect(new StringType(), ...$valueTypes);
119117

120118
$returnType = AccessoryArrayListType::intersectWith(TypeCombinator::intersect(new ArrayType(new IntegerType(), $returnValueType)));
119+
if ($isInputNonEmptyString || ($encoding === null && !$this->phpVersion->strSplitReturnsEmptyArray())) {
120+
$returnType = TypeCombinator::intersect($returnType, new NonEmptyArrayType());
121+
}
122+
if (!isset($splitLength) && !$this->phpVersion->throwsValueErrorForInternalFunctions()) {
123+
$returnType = TypeCombinator::union($returnType, new ConstantBooleanType(false));
124+
}
121125

122-
return $isInputNonEmptyString || ($encoding === null && !$this->phpVersion->strSplitReturnsEmptyArray())
123-
? TypeCombinator::intersect($returnType, new NonEmptyArrayType())
124-
: $returnType;
126+
return $returnType;
125127
}
126128

127129
/**

tests/PHPStan/Analyser/data/str-split-php74.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ public function legacyTest() {
2828
assertType('false', $strSplitConstantStringWithFailureSplitLength);
2929

3030
$strSplitConstantStringWithInvalidSplitLengthType = str_split('abcdef', []);
31-
assertType('non-empty-list<lowercase-string&non-empty-string>|false', $strSplitConstantStringWithInvalidSplitLengthType);
31+
assertType('non-empty-list<lowercase-string&non-empty-string>', $strSplitConstantStringWithInvalidSplitLengthType);
3232

3333
$strSplitConstantStringWithVariableStringAndConstantSplitLength = str_split(doFoo() ? 'abcdef' : 'ghijkl', 1);
3434
assertType("array{'a', 'b', 'c', 'd', 'e', 'f'}|array{'g', 'h', 'i', 'j', 'k', 'l'}", $strSplitConstantStringWithVariableStringAndConstantSplitLength);
3535

3636
$strSplitConstantStringWithVariableStringAndVariableSplitLength = str_split(doFoo() ? 'abcdef' : 'ghijkl', doFoo() ? 1 : 2);
37-
assertType('non-empty-list<lowercase-string&non-empty-string>|false', $strSplitConstantStringWithVariableStringAndVariableSplitLength);
37+
assertType('non-empty-list<lowercase-string&non-empty-string>', $strSplitConstantStringWithVariableStringAndVariableSplitLength);
3838

3939
}
4040
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php // lint >= 8.2
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug7580Types;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
assertType('array{}', mb_str_split('', 1));
10+
11+
assertType('array{\'x\'}', mb_str_split('x', 1));
12+
13+
$v = (string) (mt_rand() === 0 ? '' : 'x');
14+
assertType('\'\'|\'x\'', $v);
15+
assertType('array{}|array{\'x\'}', mb_str_split($v, 1));
16+
17+
function x(): string { throw new \Exception(); };
18+
$v = x();
19+
assertType('string', $v);
20+
assertType('list<non-empty-string>', mb_str_split($v, 1));

tests/PHPStan/Analyser/nsrt/bug-7580.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
<?php declare(strict_types = 1);
1+
<?php // lint < 8.2
2+
3+
declare(strict_types = 1);
24

35
namespace Bug7580Types;
46

0 commit comments

Comments
 (0)