Skip to content

Commit b1b7782

Browse files
authored
More precise types for preg_match greater than 0
1 parent 3dd5a01 commit b1b7782

File tree

2 files changed

+80
-2
lines changed

2 files changed

+80
-2
lines changed

src/Analyser/TypeSpecifier.php

+18-2
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,11 @@ public function specifyTypesInCondition(
242242
$expr->left instanceof FuncCall
243243
&& count($expr->left->getArgs()) >= 1
244244
&& $expr->left->name instanceof Name
245-
&& in_array(strtolower((string) $expr->left->name), ['count', 'sizeof', 'strlen', 'mb_strlen'], true)
245+
&& in_array(strtolower((string) $expr->left->name), ['count', 'sizeof', 'strlen', 'mb_strlen', 'preg_match'], true)
246246
&& (
247247
!$expr->right instanceof FuncCall
248248
|| !$expr->right->name instanceof Name
249-
|| !in_array(strtolower((string) $expr->right->name), ['count', 'sizeof', 'strlen', 'mb_strlen'], true)
249+
|| !in_array(strtolower((string) $expr->right->name), ['count', 'sizeof', 'strlen', 'mb_strlen', 'preg_match'], true)
250250
)
251251
) {
252252
$inverseOperator = $expr instanceof Node\Expr\BinaryOp\Smaller
@@ -336,6 +336,22 @@ public function specifyTypesInCondition(
336336
}
337337
}
338338

339+
if (
340+
!$context->null()
341+
&& $expr->right instanceof FuncCall
342+
&& count($expr->right->getArgs()) >= 3
343+
&& $expr->right->name instanceof Name
344+
&& in_array(strtolower((string) $expr->right->name), ['preg_match'], true)
345+
&& IntegerRangeType::fromInterval(0, null)->isSuperTypeOf($leftType)->yes()
346+
) {
347+
return $this->specifyTypesInCondition(
348+
$scope,
349+
new Expr\BinaryOp\NotIdentical($expr->right, new ConstFetch(new Name('false'))),
350+
$context,
351+
$rootExpr,
352+
);
353+
}
354+
339355
if (
340356
!$context->null()
341357
&& $expr->right instanceof FuncCall
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php // lint >= 7.4
2+
3+
namespace Bug11293;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
public function sayHello(string $s): void
10+
{
11+
if (preg_match('/data-(\d{6})\.json$/', $s, $matches) > 0) {
12+
assertType('array{string, non-falsy-string&numeric-string}', $matches);
13+
}
14+
}
15+
16+
public function sayHello2(string $s): void
17+
{
18+
if (preg_match('/data-(\d{6})\.json$/', $s, $matches) === 1) {
19+
assertType('array{string, non-falsy-string&numeric-string}', $matches);
20+
}
21+
}
22+
23+
public function sayHello3(string $s): void
24+
{
25+
if (preg_match('/data-(\d{6})\.json$/', $s, $matches) >= 1) {
26+
assertType('array{string, non-falsy-string&numeric-string}', $matches);
27+
}
28+
}
29+
30+
public function sayHello4(string $s): void
31+
{
32+
if (preg_match('/data-(\d{6})\.json$/', $s, $matches) <= 0) {
33+
assertType('array{}', $matches);
34+
35+
return;
36+
}
37+
38+
assertType('array{string, non-falsy-string&numeric-string}', $matches);
39+
}
40+
41+
public function sayHello5(string $s): void
42+
{
43+
if (preg_match('/data-(\d{6})\.json$/', $s, $matches) < 1) {
44+
assertType('array{}', $matches);
45+
46+
return;
47+
}
48+
49+
assertType('array{string, non-falsy-string&numeric-string}', $matches);
50+
}
51+
52+
public function sayHello6(string $s): void
53+
{
54+
if (1 > preg_match('/data-(\d{6})\.json$/', $s, $matches)) {
55+
assertType('array{}', $matches);
56+
57+
return;
58+
}
59+
60+
assertType('array{string, non-falsy-string&numeric-string}', $matches);
61+
}
62+
}

0 commit comments

Comments
 (0)