32
32
final class RegexArrayShapeMatcher
33
33
{
34
34
35
+ /**
36
+ * Pass this into $flagsType as well if the library supports emulating PREG_UNMATCHED_AS_NULL on PHP 7.2 and 7.3
37
+ */
38
+ public const PREG_UNMATCHED_AS_NULL_ON_72_73 = 2048 ;
39
+
35
40
private static ?Parser $ parser = null ;
36
41
37
42
public function __construct (
@@ -40,7 +45,7 @@ public function __construct(
40
45
{
41
46
}
42
47
43
- public function matchType (Type $ patternType , ?Type $ flagsType , TrinaryLogic $ wasMatched, bool $ supportsUnmatchedAsNullOn72 = false ): ?Type
48
+ public function matchType (Type $ patternType , ?Type $ flagsType , TrinaryLogic $ wasMatched ): ?Type
44
49
{
45
50
if ($ wasMatched ->no ()) {
46
51
return new ConstantArrayType ([], []);
@@ -53,19 +58,22 @@ public function matchType(Type $patternType, ?Type $flagsType, TrinaryLogic $was
53
58
54
59
$ flags = null ;
55
60
if ($ flagsType !== null ) {
56
- if (
57
- !$ flagsType instanceof ConstantIntegerType
58
- || !in_array ($ flagsType ->getValue (), [PREG_OFFSET_CAPTURE , PREG_UNMATCHED_AS_NULL , PREG_OFFSET_CAPTURE | PREG_UNMATCHED_AS_NULL ], true )
59
- ) {
61
+ if (!$ flagsType instanceof ConstantIntegerType) {
60
62
return null ;
61
63
}
62
64
63
- $ flags = $ flagsType ->getValue ();
65
+ /** @var int-mask<PREG_OFFSET_CAPTURE | PREG_UNMATCHED_AS_NULL | self::PREG_UNMATCHED_AS_NULL_ON_72_73> $flags */
66
+ $ flags = $ flagsType ->getValue () & (PREG_OFFSET_CAPTURE | PREG_UNMATCHED_AS_NULL | self ::PREG_UNMATCHED_AS_NULL_ON_72_73 );
67
+
68
+ // some other unsupported/unexpected flag was passed in
69
+ if ($ flags !== $ flagsType ->getValue ()) {
70
+ return null ;
71
+ }
64
72
}
65
73
66
74
$ matchedTypes = [];
67
75
foreach ($ constantStrings as $ constantString ) {
68
- $ matched = $ this ->matchRegex ($ constantString ->getValue (), $ flags , $ wasMatched, $ supportsUnmatchedAsNullOn72 );
76
+ $ matched = $ this ->matchRegex ($ constantString ->getValue (), $ flags , $ wasMatched );
69
77
if ($ matched === null ) {
70
78
return null ;
71
79
}
@@ -81,9 +89,9 @@ public function matchType(Type $patternType, ?Type $flagsType, TrinaryLogic $was
81
89
}
82
90
83
91
/**
84
- * @param int-mask<PREG_OFFSET_CAPTURE|PREG_UNMATCHED_AS_NULL>|null $flags
92
+ * @param int-mask<PREG_OFFSET_CAPTURE|PREG_UNMATCHED_AS_NULL|self::PREG_UNMATCHED_AS_NULL_ON_72_73 >|null $flags
85
93
*/
86
- private function matchRegex (string $ regex , ?int $ flags , TrinaryLogic $ wasMatched, bool $ supportsUnmatchedAsNullOn72 ): ?Type
94
+ private function matchRegex (string $ regex , ?int $ flags , TrinaryLogic $ wasMatched ): ?Type
87
95
{
88
96
$ parseResult = $ this ->parseGroups ($ regex );
89
97
if ($ parseResult === null ) {
@@ -100,7 +108,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
100
108
$ trailingOptionals ++;
101
109
}
102
110
103
- $ valueType = $ this ->getValueType ($ flags ?? 0 , $ supportsUnmatchedAsNullOn72 );
111
+ $ valueType = $ this ->getValueType ($ flags ?? 0 );
104
112
$ onlyOptionalTopLevelGroup = $ this ->getOnlyOptionalTopLevelGroup ($ groupList );
105
113
$ onlyTopLevelAlternationId = $ this ->getOnlyTopLevelAlternationId ($ groupList );
106
114
@@ -119,7 +127,6 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
119
127
$ wasMatched ,
120
128
$ trailingOptionals ,
121
129
$ flags ?? 0 ,
122
- $ supportsUnmatchedAsNullOn72 ,
123
130
);
124
131
125
132
return TypeCombinator::union (
@@ -155,7 +162,6 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
155
162
$ wasMatched ,
156
163
$ trailingOptionals ,
157
164
$ flags ?? 0 ,
158
- $ supportsUnmatchedAsNullOn72 ,
159
165
);
160
166
161
167
$ combiTypes [] = $ combiType ;
@@ -179,7 +185,6 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
179
185
$ wasMatched ,
180
186
$ trailingOptionals ,
181
187
$ flags ?? 0 ,
182
- $ supportsUnmatchedAsNullOn72 ,
183
188
);
184
189
}
185
190
@@ -242,7 +247,6 @@ private function buildArrayType(
242
247
TrinaryLogic $ wasMatched ,
243
248
int $ trailingOptionals ,
244
249
int $ flags ,
245
- bool $ supportsUnmatchedAsNullOn72 ,
246
250
): Type
247
251
{
248
252
$ builder = ConstantArrayTypeBuilder::createEmpty ();
@@ -264,10 +268,10 @@ private function buildArrayType(
264
268
} else {
265
269
if ($ i < $ countGroups - $ trailingOptionals ) {
266
270
$ optional = false ;
267
- if ($ this ->containsUnmatchedAsNull ($ flags, $ supportsUnmatchedAsNullOn72 )) {
271
+ if ($ this ->containsUnmatchedAsNull ($ flags )) {
268
272
$ groupValueType = TypeCombinator::removeNull ($ groupValueType );
269
273
}
270
- } elseif ($ this ->containsUnmatchedAsNull ($ flags, $ supportsUnmatchedAsNullOn72 )) {
274
+ } elseif ($ this ->containsUnmatchedAsNull ($ flags )) {
271
275
$ optional = false ;
272
276
} else {
273
277
$ optional = $ captureGroup ->isOptional ();
@@ -294,9 +298,9 @@ private function buildArrayType(
294
298
return $ builder ->getArray ();
295
299
}
296
300
297
- private function containsUnmatchedAsNull (int $ flags, bool $ supportsUnmatchedAsNullOn72 ): bool
301
+ private function containsUnmatchedAsNull (int $ flags ): bool
298
302
{
299
- return ($ flags & PREG_UNMATCHED_AS_NULL ) !== 0 && ($ supportsUnmatchedAsNullOn72 || $ this ->phpVersion ->supportsPregUnmatchedAsNull ());
303
+ return ($ flags & PREG_UNMATCHED_AS_NULL ) !== 0 && (( $ flags & self :: PREG_UNMATCHED_AS_NULL_ON_72_73 ) !== 0 || $ this ->phpVersion ->supportsPregUnmatchedAsNull ());
300
304
}
301
305
302
306
private function getKeyType (int |string $ key ): Type
@@ -308,11 +312,11 @@ private function getKeyType(int|string $key): Type
308
312
return new ConstantIntegerType ($ key );
309
313
}
310
314
311
- private function getValueType (int $ flags, bool $ supportsUnmatchedAsNullOn72 ): Type
315
+ private function getValueType (int $ flags ): Type
312
316
{
313
317
$ valueType = new StringType ();
314
318
$ offsetType = IntegerRangeType::fromInterval (0 , null );
315
- if ($ this ->containsUnmatchedAsNull ($ flags, $ supportsUnmatchedAsNullOn72 )) {
319
+ if ($ this ->containsUnmatchedAsNull ($ flags )) {
316
320
$ valueType = TypeCombinator::addNull ($ valueType );
317
321
// unmatched groups return -1 as offset
318
322
$ offsetType = IntegerRangeType::fromInterval (-1 , null );
0 commit comments