8000 introduce flags to customize the parser behavior · symfony/symfony@9cb8552 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9cb8552

Browse files
committed
introduce flags to customize the parser behavior
1 parent 80f3410 commit 9cb8552

File tree

8 files changed

+309
-38
lines changed

8 files changed

+309
-38
lines changed

UPGRADE-3.1.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,51 @@ Serializer
3333
Yaml
3434
----
3535

36+
* Deprecated support for passing `true`/`false` as the second argument to the
37+
`parse()` method to trigger exceptions when an invalid type was passed.
38+
39+
Before:
40+
41+
```php
42+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', true);
43+
```
44+
45+
After:
46+
47+
```php
48+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', YAML::PARSE_EXCEPTION_ON_INVALID_TYPE);
49+
```
50+
51+
* Deprecated support for passing `true`/`false` as the third argument to the
52+
`parse()` method to toggle object support.
53+
54+
Before:
55+
56+
```php
57+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', false, true);
58+
```
59+
60+
After:
61+
62+
```php
63+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::PARSE_OBJECT);
64+
```
65+
66+
* Deprecated support for passing `true`/`false` as the fourth argument to the
67+
`parse()` method to parse objects as maps.
68+
69+
Before:
70+
71+
```php
72+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', false, false, true);
73+
```
74+
75+
After:
76+
77+
```php
78+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::PARSE_OBJECT_FOR_MAP);
79+
```
80+
3681
* Deprecated support for passing `true`/`false` as the third argument to the `dump()` methods to toggle object support.
3782

3883
Before:

UPGRADE-4.0.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,51 @@ Serializer
2424
Yaml
2525
----
2626

27+
* Removed support for passing `true`/`false` as the second argument to the
28+
`parse()` method to trigger exceptions when an invalid type was passed.
29+
30+
Before:
31+
32+
```php
33+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', true);
34+
```
35+
36+
After:
37+
38+
```php
39+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', YAML::PARSE_EXCEPTION_ON_INVALID_TYPE);
40+
```
41+
42+
* Removed support for passing `true`/`false` as the third argument to the
43+
`parse()` method to toggle object support.
44+
45+
Before:
46+
47+
```php
48+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', false, true);
49+
```
50+
51+
After:
52+
53+
```php
54+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::PARSE_OBJECT);
55+
```
56+
57+
* Removed support for passing `true`/`false` as the fourth argument to the
58+
`parse()` method to parse objects as maps.
59+
60+
Before:
61+
62+
```php
63+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', false, false, true);
64+
```
65+
66+
After:
67+
68+
```php
69+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::PARSE_OBJECT_FOR_MAP);
70+
```
71+
2772
* Removed support for passing `true`/`false` as the third argument to the `dump()` methods to toggle object support.
2873

2974
Before:

src/Symfony/Component/Yaml/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ CHANGELOG
44
3.1.0
55
-----
66

7+
* Added support for customizing the YAML parser behavior through an optional bit field:
8+
9+
```php
10+
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::EXCEPTION_ON_INVALID_TYPE | Yaml::PARSE_OBJECT | Yaml::PARSE_OBJECT_FOR_MAP);
11+
```
12+
713
* Added support for customizing the dumped YAML string through an optional bit field:
814

915
```php

src/Symfony/Component/Yaml/Inline.php

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,51 @@ class Inline
3030
/**
3131
* Converts a YAML string to a PHP array.
3232
*
33-
* @param string $value A YAML string
34-
* @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
35-
* @param bool $objectSupport true if object support is enabled, false otherwise
36-
* @param bool $objectForMap true if maps should return a stdClass instead of array()
37-
* @param array $references Mapping of variable names to values
33+
* @param string $value A YAML string
34+
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
35+
* @param array $references Mapping of variable names to values
3836
*
3937
* @return array A PHP array representing the YAML string
4038
*
4139
* @throws ParseException
4240
*/
43-
public static function parse($value, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false, $references = array())
41+
public static function parse($value, $flags = 0, $references = array())
4442
{
45-
self::$exceptionOnInvalidType = $exceptionOnInvalidType;
46-
self::$objectSupport = $objectSupport;
47-
self::$objectForMap = $objectForMap;
43+
if (is_bool($flags)) {
44+
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
45+
46+
if ($flags) {
47+
$flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE;
48+
} else {
49+
$flags = 0;
50+
}
51+
}
52+
53+
if (func_num_args() >= 3 && !is_array($references)) {
54+
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED);
55+
56+
if ($references) {
57+
$flags |= Yaml::PARSE_OBJECT;
58+
}
59+
60+
if (func_num_args() >= 4) {
61+
@trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED);
62+
63+
if (func_get_arg(3)) {
64+
$flags |= Yaml::PARSE_OBJECT_FOR_MAP;
65+
}
66+
}
67+
68+
if (func_num_args() >= 5) {
69+
$references = func_get_arg(4);
70+
} else {
71+
$references = array();
72+
}
73+
}
74+
75+
self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
76+
self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
77+
self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
4878

4979
$value = trim($value);
5080

src/Symfony/Component/Yaml/Parser.php

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,41 @@ public function __construct($offset = 0)
4141
/**
4242
* Parses a YAML string to a PHP value.
4343
*
44-
* @param string $value A YAML string
45-
* @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
46-
* @param bool $objectSupport true if object support is enabled, false otherwise
47-
* @param bool $objectForMap true if maps should return a stdClass instead of array()
44+
* @param string $value A YAML string
45+
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
4846
*
4947
* @return mixed A PHP value
5048
*
5149
* @throws ParseException If the YAML is not valid
5250
*/
53-
public function parse($value, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false)
51+
public function parse($value, $flags = 0)
5452
{
53+
if (is_bool($flags)) {
54+
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
55+
56+
if ($flags) {
57+
$flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE;
58+
} else {
59+
$flags = 0;
60+
}
61+
}
62+
63+
if (func_num_args() >= 3) {
64+
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED);
65+
66+
if (func_get_arg(2)) {
67+
$flags |= Yaml::PARSE_OBJECT;
68+
}
69+
}
70+
71+
if (func_num_args() >= 4) {
72+
@trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED);
73+
74+
if (func_get_arg(3)) {
75+
$flags |= Yaml::PARSE_OBJECT_FOR_MAP;
76+
}
77+
}
78+
5579
if (!preg_match('//u', $value)) {
5680
throw new ParseException('The YAML value does not appear to be valid UTF-8.');
5781
}
@@ -95,7 +119,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
95119
$c = $this->getRealCurrentLineNb() + 1;
96120
$parser = new self($c);
97121
$parser->refs = &$this->refs;
98-
$data[] = $parser->parse($this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport, $objectForMap);
122+
$data[] = $parser->parse($this->getNextEmbedBlock(null, true), $flags);
99123
} else {
100124
if (isset($values['leadspaces'])
101125
&& preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches)
@@ -110,9 +134,9 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
110134
$block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + strlen($values['leadspaces']) + 1);
111135
}
112136

113-
$data[] = $parser->parse($block, $exceptionOnInvalidType, $objectSupport, $objectForMap);
137+
$data[] = $parser->parse($block, $flags);
114138
} else {
115-
$data[] = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);
139+
$data[] = $this->parseValue($values['value'], $flags, $context);
116140
}
117141
}
118142
if ($isRef) {
@@ -125,7 +149,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
125149
$context = 'mapping';
126150

127151
// force correct settings
128-
Inline::parse(null, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
152+
Inline::parse(null, $flags, $this->refs);
129153
B93C try {
130154
$key = Inline::parseScalar($values['key']);
131155
} catch (ParseException $e) {
@@ -169,7 +193,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
169193
$c = $this->getRealCurrentLineNb() + 1;
170194
$parser = new self($c);
171195
$parser->refs = &$this->refs;
172-
$parsed = $parser->parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap);
196+
$parsed = $parser->parse($value, $flags);
173197

174198
if (!is_array($parsed)) {
175199
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
@@ -220,15 +244,15 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
220244
$c = $this->getRealCurrentLineNb() + 1;
221245
$parser = new self($c);
222246
$parser->refs = &$this->refs;
223-
$value = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport, $objectForMap);
247+
$value = $parser->parse($this->getNextEmbedBlock(), $flags);
224248
// Spec: Keys MUST be unique; first one wins.
225249
// But overwriting is allowed when a merge node is used in current block.
226250
if ($allowOverwrite || !isset($data[$key])) {
227251
$data[$key] = $value;
228252
}
229253
}
230254
} else {
231-
$value = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);
255+
$value = $this->parseValue($values['value'], $flags, $context);
232256
// Spec: Keys MUST be unique; first one wins.
233257
// But overwriting is allowed when a merge node is used in current block.
234258
if ($allowOverwrite || !isset($data[$key])) {
@@ -247,7 +271,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
247271
// 1-liner optionally followed by newline(s)
248272
if (is_string($value) && $this->lines[0] === trim($value)) {
249273
try {
250-
$value = Inline::parse($this->lines[0], $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
274+
$value = Inline::parse($this->lines[0], $flags, $this->refs);
251275
} catch (ParseException $e) {
252276
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
253277
$e->setSnippet($this->currentLine);
@@ -301,7 +325,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
301325
mb_internal_encoding($mbEncoding);
302326
}
303327

304-
if ($objectForMap && !is_object($data)) {
328+
if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && !is_object($data)) {
305329
$data = (object) $data;
306330
}
307331

@@ -462,17 +486,15 @@ private function moveToPreviousLine()
462486
/**
463487
* Parses a YAML value.
464488
*
465-
* @param string $value A YAML value
466-
* @param bool $exceptionOnInvalidType True if an exception must be thrown on invalid types false otherwise
467-
* @param bool $objectSupport True if object support is enabled, false otherwise
468-
* @param bool $objectForMap true if maps should return a stdClass instead of array()
469-
* @param string $context The parser context (either sequence or mapping)
489+
* @param string $value A YAML value
490+
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
491+
* @param string $context The parser context (either sequence or mapping)
470492
*
471493
* @return mixed A PHP value
472494
*
473495
* @throws ParseException When reference does not exist
474496
*/
475-
private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $context)
497+
private function parseValue($value, $flags, $context)
476498
{
477499
if (0 === strpos($value, '*')) {
478500
if (false !== $pos = strpos($value, '#')) {
@@ -495,7 +517,7 @@ private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $ob
495517
}
496518

497519
try {
498-
$parsedValue = Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
520+
$parsedValue = Inline::parse($value, $flags, $this->refs);
499521

500522
if ('mapping' === $context && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
501523
throw new ParseException('A colon cannot be used in an unquoted mapping value.');

src/Symfony/Component/Yaml/Tests/InlineTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Yaml\Tests;
1313

1414
use Symfony\Component\Yaml\Inline;
15+
use Symfony\Component\Yaml\Yaml;
1516

1617
class InlineTest extends \PHPUnit_Framework_TestCase
1718
{
@@ -27,6 +28,17 @@ public function testParse($yaml, $value)
2728
* @dataProvider getTestsForParseWithMapObjects
2829
*/
2930
public function testParseWithMapObjects($yaml, $value)
31+
{
32+
$actual = Inline::parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP);
33+
34+
$this->assertSame(serialize($value), serialize($actual));
35+
}
36+
37+
/**
38+
* @group legacy
39+
* @dataProvider getTestsForParseWithMapObjects
40+
*/
41+
public function testParseWithMapObjectsPassingTrue($yaml, $value)
3042
{
3143
$actual = Inline::parse($yaml, false, false, true);
3244

@@ -142,6 +154,15 @@ public function testParseScalarWithCorrectlyQuotedStringShouldReturnString()
142154
* @dataProvider getDataForParseReferences
143155
*/
144156
public function testParseReferences($yaml, $expected)
157+
{
158+
$this->assertSame($expected, Inline::parse($yaml, 0, array('var' => 'var-value')));
159+
}
160+
161+
/**
162+
* @group legacy
163+
* @dataProvider getDataForParseReferences
164+
*/
165+
public function testParseReferencesAsFifthArgument($yaml, $expected)
145166
{
146167
$this->assertSame($expected, Inline::parse($yaml, false, false, false, array('var' => 'var-value')));
147168
}
@@ -161,6 +182,19 @@ public function getDataForParseReferences()
161182
}
162183

163184
public function testParseMapReferenceInSequence()
185+
{
186+
$foo = array(
187+
'a' => 'Steve',
188+
'b' => 'Clark',
189+
'c' => 'Brian',
190+
);
191+
$this->assertSame(array($foo), Inline::parse('[*foo]', 0, array('foo' => $foo)));
192+
}
193+
194+
/**
195+
* @group legacy
196+
*/
197+
public function testParseMapReferenceInSequenceAsFifthArgument()
164198
{
165199
$foo = array(
166200
'a' => 'Steve',

0 commit comments

Comments
 (0)
0