44
55namespace TypePHP \Validator ;
66
7+ use PHPStan \PhpDocParser \Ast \ConstExpr \ConstExprIntegerNode ;
78use PHPStan \PhpDocParser \Ast \ConstExpr \ConstExprStringNode ;
89use PHPStan \PhpDocParser \Ast \Type \ArrayShapeNode ;
10+ use PHPStan \PhpDocParser \Ast \Type \IdentifierTypeNode ;
911use PHPStan \PhpDocParser \Ast \Type \TypeNode ;
1012use TypePHP \Internal \ErrorFactory ;
1113use TypePHP \Internal \ErrorMessage ;
1214use TypePHP \Internal \TypeFormatter ;
1315
1416/**
15- * @internal Class for validating array shapes like array<1: string,2: int> .
17+ * @internal Class for validating array shapes and tuple shapes like array{0: string, 1: int} or array{string, int} .
1618 */
1719final class ArrayShapeValidator implements TypeValidatorInterface
1820{
@@ -24,30 +26,38 @@ public function validate(mixed $value, TypeNode $node, string $context, TypeVali
2426
2527 /** @var ArrayShapeNode $node */
2628 $ knownKeys = [];
29+ $ nextAutoIndex = 0 ;
2730
2831 foreach ($ node ->items as $ item ) {
2932 $ key = null ;
33+
3034 if ($ item ->keyName instanceof ConstExprStringNode) {
3135 $ key = $ item ->keyName ->value ;
36+ } elseif ($ item ->keyName instanceof ConstExprIntegerNode) {
37+ $ key = (int ) $ item ->keyName ->value ;
38+ $ nextAutoIndex = max ($ nextAutoIndex , $ key + 1 );
39+ } elseif ($ item ->keyName instanceof IdentifierTypeNode) {
40+ $ key = $ item ->keyName ->name ;
3241 } elseif ($ item ->keyName !== null ) {
3342 $ key = (string ) $ item ->keyName ;
43+ } else {
44+ $ key = $ nextAutoIndex ;
45+ $ nextAutoIndex ++;
3446 }
3547
36- if ($ key !== null ) {
37- $ knownKeys [$ key ] = true ;
38-
39- if (! \array_key_exists ($ key , $ value )) {
40- if (! $ item ->optional ) {
41- return ErrorFactory::createError ($ context . " is missing required key ' $ key' " );
42- }
48+ $ knownKeys [$ key ] = true ;
4349
44- continue ;
50+ if (! \array_key_exists ($ key , $ value )) {
51+ if (! $ item ->optional ) {
52+ return ErrorFactory::createError ($ context . " is missing required key ' $ key' " );
4553 }
4654
47- $ err = $ registry ->validate ($ value [$ key ], $ item ->valueType , $ context . "[' " . $ key . "'] " );
48- if ($ err !== null ) {
49- return $ err ;
50- }
55+ continue ;
56+ }
57+
58+ $ err = $ registry ->validate ($ value [$ key ], $ item ->valueType , $ context . "[' " . $ key . "'] " );
59+ if ($ err !== null ) {
60+ return $ err ;
5161 }
5262 }
5363
@@ -81,4 +91,4 @@ public function validate(mixed $value, TypeNode $node, string $context, TypeVali
8191
8292 return null ;
8393 }
84- }
94+ }
0 commit comments