Skip to content

Commit 0f3622a

Browse files
authored
RegexArrayShapeMatcher - Fix PREG_UNMATCHED_AS_NULL with optional leading groups
1 parent 8fad6d5 commit 0f3622a

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

src/Type/Php/RegexArrayShapeMatcher.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ private function buildArrayType(
271271
} else {
272272
if ($i < $countGroups - $trailingOptionals) {
273273
$optional = false;
274-
if ($this->containsUnmatchedAsNull($flags)) {
274+
if ($this->containsUnmatchedAsNull($flags) && !$captureGroup->isOptional()) {
275275
$groupValueType = TypeCombinator::removeNull($groupValueType);
276276
}
277277
} elseif ($this->containsUnmatchedAsNull($flags)) {

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,39 @@ function unmatchedAsNullWithOptionalGroup(string $s): void {
2929
assertType('array{}|array{string, string|null}', $matches);
3030
}
3131

32+
function bug11331a(string $url):void {
33+
// group a is actually optional as the entire (?:...) around it is optional
34+
if (preg_match('{^
35+
(?:
36+
(?<a>.+)
37+
)?
38+
(?<b>.+)}mix', $url, $matches, PREG_UNMATCHED_AS_NULL)) {
39+
assertType('array{0: string, a: string|null, 1: string|null, b: string, 2: string}', $matches);
40+
}
41+
}
42+
43+
function bug11331b(string $url):void {
44+
if (preg_match('{^
45+
(?:
46+
(?<a>.+)
47+
)?
48+
(?<b>.+)?}mix', $url, $matches, PREG_UNMATCHED_AS_NULL)) {
49+
assertType('array{0: string, a: string|null, 1: string|null, b: string|null, 2: string|null}', $matches);
50+
}
51+
}
52+
53+
function bug11331c(string $url):void {
54+
if (preg_match('{^
55+
(?:
56+
(?:https?|git)://([^/]+)/ (?# group 1 here can be null if group 2 matches)
57+
| (?# the alternation making it so that only either should match)
58+
git@([^:]+):/? (?# group 2 here can be null if group 1 matches)
59+
)
60+
([^/]+)
61+
/
62+
([^/]+?)
63+
(?:\.git|/)?
64+
$}x', $url, $matches, PREG_UNMATCHED_AS_NULL)) {
65+
assertType('array{string, string|null, string|null, string, string}', $matches);
66+
}
67+
}

0 commit comments

Comments
 (0)