@@ -35,6 +35,7 @@ class Parser
35
35
private $ refs = array ();
36
36
private $ skippedLineNumbers = array ();
37
37
private $ locallySkippedLineNumbers = array ();
38
+ private $ refsBeingParsed = array ();
38
39
39
40
public function __construct ()
40
41
{
@@ -212,6 +213,7 @@ private function doParse($value, $flags)
212
213
213
214
if (isset ($ values ['value ' ]) && self ::preg_match ('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u ' , $ values ['value ' ], $ matches )) {
214
215
$ isRef = $ matches ['ref ' ];
216
+ $ this ->refsBeingParsed [] = $ isRef ;
215
217
$ values ['value ' ] = $ matches ['value ' ];
216
218
}
217
219
@@ -244,6 +246,7 @@ private function doParse($value, $flags)
244
246
}
245
247
if ($ isRef ) {
246
248
$ this ->refs [$ isRef ] = end ($ data );
249
+ array_pop ($ this ->refsBeingParsed );
247
250
}
248
251
} elseif (
249
252
self ::preg_match ('#^(?P<key>(?:![^\s]++\s++)?(?: ' .Inline::REGEX_QUOTED_STRING .'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(\s++(?P<value>.+))?$#u ' , rtrim ($ this ->currentLine ), $ values )
@@ -287,6 +290,10 @@ private function doParse($value, $flags)
287
290
if (isset ($ values ['value ' ][0 ]) && '* ' === $ values ['value ' ][0 ]) {
288
291
$ refName = substr (rtrim ($ values ['value ' ]), 1 );
289
292
if (!array_key_exists ($ refName , $ this ->refs )) {
293
+ if (false !== $ pos = array_search ($ refName , $ this ->refsBeingParsed , true )) {
294
+ throw new ParseException (sprintf ('Circular reference [%s, %s] detected for reference "%s". ' , implode (', ' , \array_slice ($ this ->refsBeingParsed , $ pos )), $ refName , $ refName ), $ this ->currentLineNb + 1 , $ this ->currentLine , $ this ->filename );
295
+ }
296
+
290
297
throw new ParseException (sprintf ('Reference "%s" does not exist. ' , $ refName ), $ this ->getRealCurrentLineNb () + 1 , $ this ->currentLine , $ this ->filename );
291
298
}
292
299
@@ -340,6 +347,7 @@ private function doParse($value, $flags)
340
347
}
341
348
} elseif ('<< ' !== $ key && isset ($ values ['value ' ]) && self ::preg_match ('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u ' , $ values ['value ' ], $ matches )) {
342
349
$ isRef = $ matches ['ref ' ];
350
+ $ this ->refsBeingParsed [] = $ isRef ;
343
351
$ values ['value ' ] = $ matches ['value ' ];
344
352
}
345
353
@@ -395,6 +403,7 @@ private function doParse($value, $flags)
395
403
}
396
404
if ($ isRef ) {
397
405
$ this ->refs [$ isRef ] = $ data [$ key ];
406
+ array_pop ($ this ->refsBeingParsed );
398
407
}
399
408
} else {
400
409
// multiple documents are not supported
@@ -500,6 +509,7 @@ private function parseBlock($offset, $yaml, $flags)
500
509
$ parser ->totalNumberOfLines = $ this ->totalNumberOfLines ;
501
510
$ parser ->skippedLineNumbers = $ skippedLineNumbers ;
502
511
$ parser ->refs = &$ this ->refs ;
512
+ $ parser ->refsBeingParsed = $ this ->refsBeingParsed ;
503
513
504
514
return $ parser ->doParse ($ yaml , $ flags );
505
515
}
@@ -689,6 +699,10 @@ private function parseValue($value, $flags, $context)
689
699
}
690
700
691
701
if (!array_key_exists ($ value , $ this ->refs )) {
702
+ if (false !== $ pos = array_search ($ value , $ this ->refsBeingParsed , true )) {
703
+ throw new ParseException (sprintf ('Circular reference [%s, %s] detected for reference "%s". ' , implode (', ' , \array_slice ($ this ->refsBeingParsed , $ pos )), $ value , $ value ), $ this ->currentLineNb + 1 , $ this ->currentLine , $ this ->filename );
704
+ }
705
+
692
706
throw new ParseException (sprintf ('Reference "%s" does not exist. ' , $ value ), $ this ->currentLineNb + 1 , $ this ->currentLine , $ this ->filename );
693
707
}
694
708
0 commit comments