Rename array to sequence

This commit is contained in:
Fabien Potencier
2024-06-16 19:50:38 +02:00
parent 5157402a77
commit c44be99a84
22 changed files with 102 additions and 87 deletions
+3
View File
@@ -4,6 +4,9 @@
* Deprecate `Twig\ExpressionParser\parseHashExpression()` in favor of
`Twig\ExpressionParser::parseMappingExpression()`
* Deprecate `Twig\ExpressionParser\parseArrayExpression()`` in favor of
`Twig\ExpressionParser::parseSequenceExpression()`
# 3.10.3 (2024-05-16)
* Fix missing ; in generated code
+3 -3
View File
@@ -40,7 +40,7 @@ standards:
{{ foo ~ bar }}
{{ true ? true : false }}
* Put exactly one space after the ``:`` sign in mappings and ``,`` in arrays
* Put exactly one space after the ``:`` sign in mappings and ``,`` in sequences
and mappings:
.. code-block:: twig
@@ -80,8 +80,8 @@ standards:
{{ foo|default('foo') }}
{{ range(1..10) }}
* Do not put any spaces before and after the opening and the closing of arrays
and mappings:
* Do not put any spaces before and after the opening and the closing of
sequences and mappings:
.. code-block:: twig
+3
View File
@@ -51,6 +51,9 @@ Parser
* The ``Twig\ExpressionParser::parseHashExpression()`` method is deprecated, use
``Twig\ExpressionParser::parseMappingExpression()`` instead.
* The ``Twig\ExpressionParser::parseArrayExpression()`` method is deprecated, use
``Twig\ExpressionParser::parseSequenceExpression()`` instead.
Templates
---------
+1 -1
View File
@@ -50,6 +50,6 @@ Arguments
---------
* ``mime``: The mime type
* ``parameters``: An array of parameters
* ``parameters``: A mapping of parameters
.. _RFC 2397: https://tools.ietf.org/html/rfc2397
+10 -4
View File
@@ -1,14 +1,20 @@
``keys``
========
The ``keys`` filter returns the keys of an array. It is useful when you want to
iterate over the keys of an array:
The ``keys`` filter returns the keys of a sequence or a mapping. It is useful
when you want to iterate over the keys of a sequence or a mapping:
.. code-block:: twig
{% for key in array|keys %}
...
{% for key in [1, 2, 3, 4]|keys %}
{{ key }}
{% endfor %}
{# outputs: 1 2 3 4 #}
{% for key in {a: 'a_value', b: 'b_value'}|keys %}
{{ key }}
{% endfor %}
{# outputs: a b #}
.. note::
+4 -2
View File
@@ -1,7 +1,9 @@
``merge``
=========
The ``merge`` filter merges an array with another array:
The ``merge`` filter merges sequences and mappings.
The ``merge`` filter also works on sequences:
.. code-block:: twig
@@ -29,7 +31,7 @@ overridden.
.. tip::
If you want to ensure that some values are defined in an array (by given
If you want to ensure that some values are defined in a mapping (by given
default values), reverse the two elements in the call:
.. code-block:: twig
+2 -2
View File
@@ -1,7 +1,7 @@
``sort``
========
The ``sort`` filter sorts an array:
The ``sort`` filter sorts sequences and mappings:
.. code-block:: twig
@@ -15,7 +15,7 @@ The ``sort`` filter sorts an array:
association. It supports Traversable objects by transforming
those to arrays.
You can pass an arrow function to sort the array:
You can pass an arrow function to configure the sorting:
.. code-block:: html+twig
+1 -1
View File
@@ -11,7 +11,7 @@ of strings:
You can also pass a ``limit`` argument:
* If ``limit`` is positive, the returned array will contain a maximum of
* If ``limit`` is positive, the returned sequence will contain a maximum of
limit elements with the last element containing the rest of string;
* If ``limit`` is negative, all components except the last -limit are
+2 -2
View File
@@ -1,8 +1,8 @@
``url_encode``
==============
The ``url_encode`` filter percent encodes a given string as URL segment
or an array as query string:
The ``url_encode`` filter percent encodes a given string as URL segment or a
mapping as query string:
.. code-block:: twig
+1 -1
View File
@@ -1,7 +1,7 @@
``cycle``
=========
The ``cycle`` function cycles on an array of values:
The ``cycle`` function cycles on a sequence or mapping:
.. code-block:: twig
+4 -4
View File
@@ -1,8 +1,8 @@
``for``
=======
Loop over each item in a sequence. For example, to display a list of users
provided in a variable called ``users``:
Loop over each item in a sequence or a mapping. For example, to display a list
of users provided in a variable called ``users``:
.. code-block:: html+twig
@@ -15,8 +15,8 @@ provided in a variable called ``users``:
.. note::
A sequence can be either an array or an object implementing the
``Traversable`` interface.
A sequence or a mapping can be either an array or an object implementing
the ``Traversable`` interface.
If you do need to iterate over a sequence of numbers, you can use the ``..``
operator:
+5 -3
View File
@@ -12,7 +12,7 @@ In the simplest form you can use it to test if an expression evaluates to
<p>Our website is in maintenance mode. Please, come back later.</p>
{% endif %}
You can also test if an array is not empty:
You can also test if a sequence or a mapping is not empty:
.. code-block:: html+twig
@@ -71,8 +71,10 @@ use more complex ``expressions`` there too:
INF (Infinity) true
whitespace-only string true
string "0" or '0' false
empty array false
empty sequence false
empty mapping false
null false
non-empty array true
non-empty sequence true
non-empty mapping true
object true
====================== ====================
+8 -8
View File
@@ -102,7 +102,7 @@ If a variable or attribute does not exist, the behavior depends on the
For convenience's sake ``foo.bar`` does the following things on the PHP
layer:
* check if ``foo`` is an array and ``bar`` a valid element;
* check if ``foo`` is a sequence or a mapping and ``bar`` a valid element;
* if not, and if ``foo`` is an object, check that ``bar`` is a valid property;
* if not, and if ``foo`` is an object, check that ``bar`` is a valid method
(even if ``bar`` is the constructor - use ``__construct()`` instead);
@@ -115,7 +115,7 @@ If a variable or attribute does not exist, the behavior depends on the
Twig also supports a specific syntax for accessing items on PHP arrays,
``foo['bar']``:
* check if ``foo`` is an array and ``bar`` a valid element;
* check if ``foo`` is a sequence or a mapping and ``bar`` a valid element;
* if not, and if ``strict_variables`` is ``false``, return ``null``;
* if not, throw an exception.
@@ -531,7 +531,7 @@ exist:
writing the number down. If a dot is present the number is a float,
otherwise an integer.
* ``["foo", "bar"]``: Arrays are defined by a sequence of expressions
* ``["foo", "bar"]``: Sequences are defined by a sequence of expressions
separated by a comma (``,``) and wrapped with squared brackets (``[]``).
* ``{"foo": "bar"}``: Mappings are defined by a list of keys and values
@@ -563,7 +563,7 @@ exist:
* ``null``: ``null`` represents no specific value. This is the value returned
when a variable does not exist. ``none`` is an alias for ``null``.
Arrays and mappings can be nested:
Sequences and mappings can be nested:
.. code-block:: twig
@@ -698,8 +698,8 @@ operand is contained in the right:
.. tip::
You can use this filter to perform a containment test on strings, arrays,
or objects implementing the ``Traversable`` interface.
You can use this filter to perform a containment test on strings,
sequences, mappings, or objects implementing the ``Traversable`` interface.
To perform a negative test, use the ``not in`` operator:
@@ -785,7 +785,7 @@ The following operators don't fit into any of the other categories:
{# returns the value of foo if it is defined and not null, 'no' otherwise #}
{{ foo ?? 'no' }}
* ``...``: The spread operator can be used to expand arrays or mappings (it
* ``...``: The spread operator can be used to expand sequences or mappings (it
cannot be used to expand the arguments of a function call):
.. code-block:: twig
@@ -827,7 +827,7 @@ Operator Score of precedence Description
``**`` 200 Raises a number to the power of another
``??`` 300 Default value when a variable is null
``+``, ``-`` 500 Unary operations on numbers
``|``,``[]``,``.`` - Filters, array, mapping, and attribute access
``|``,``[]``,``.`` - Filters, sequence, mapping, and attribute access
============================= =================================== =====================================================
Without using any parentheses, the operator precedence rules are used to
+1 -1
View File
@@ -1,7 +1,7 @@
``empty``
=========
``empty`` checks if a variable is an empty string, an empty array, an empty
``empty`` checks if a variable is an empty string, an empty sequence, an empty
mapping, exactly ``false``, or exactly ``null``.
For objects that implement the ``Countable`` interface, ``empty`` will check the
+12 -5
View File
@@ -278,7 +278,7 @@ class ExpressionParser
// no break
default:
if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) {
$node = $this->parseArrayExpression();
$node = $this->parseSequenceExpression();
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) {
$node = $this->parseMappingExpression();
} elseif ($token->test(/* Token::OPERATOR_TYPE */ 8, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
@@ -320,15 +320,22 @@ class ExpressionParser
}
public function parseArrayExpression()
{
trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseSequenceExpression()" instead.', __METHOD__);
return $this->parseSequenceExpression();
}
public function parseSequenceExpression()
{
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'An array element was expected');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'A sequence element was expected');
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
if (!$first) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A sequence element must be followed by a comma');
// trailing ,?
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
@@ -346,7 +353,7 @@ class ExpressionParser
$node->addElement($this->parseExpression());
}
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened sequence is not properly closed');
return $node;
}
@@ -641,7 +648,7 @@ class ExpressionParser
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $stream->getSourceContext());
throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping).', $token->getLine(), $stream->getSourceContext());
}
} else {
$value = $this->parseExpression(0, $allowArrow);
+12 -12
View File
@@ -329,7 +329,7 @@ final class CoreExtension extends AbstractExtension
}
if (!\count($values)) {
throw new RuntimeError('The "cycle" function does not work on empty arrays.');
throw new RuntimeError('The "cycle" function does not work on empty sequences/mappings.');
}
return $values[$position % \count($values)];
@@ -399,7 +399,7 @@ final class CoreExtension extends AbstractExtension
$values = self::toArray($values);
if (0 === \count($values)) {
throw new RuntimeError('The random function cannot pick from an empty array.');
throw new RuntimeError('The random function cannot pick from an empty sequence/mapping.');
}
return $values[array_rand($values, 1)];
@@ -536,7 +536,7 @@ final class CoreExtension extends AbstractExtension
public static function replace($str, $from): string
{
if (!is_iterable($from)) {
throw new RuntimeError(\sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from)));
throw new RuntimeError(\sprintf('The "replace" filter expects a sequence/mapping or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from)));
}
return strtr($str ?? '', self::toArray($from));
@@ -633,7 +633,7 @@ final class CoreExtension extends AbstractExtension
foreach ($arrays as $argNumber => $array) {
if (!is_iterable($array)) {
throw new RuntimeError(\sprintf('The merge filter only works with arrays or "Traversable", got "%s" for argument %d.', \gettype($array), $argNumber + 1));
throw new RuntimeError(\sprintf('The merge filter only works with sequences/mappings or "Traversable", got "%s" for argument %d.', \gettype($array), $argNumber + 1));
}
$result = array_merge($result, self::toArray($array));
@@ -907,7 +907,7 @@ final class CoreExtension extends AbstractExtension
if ($array instanceof \Traversable) {
$array = iterator_to_array($array);
} elseif (!\is_array($array)) {
throw new RuntimeError(\sprintf('The sort filter only works with arrays or "Traversable", got "%s".', \gettype($array)));
throw new RuntimeError(\sprintf('The sort filter only works with sequences/mappings or "Traversable", got "%s".', \gettype($array)));
}
if (null !== $arrow) {
@@ -1424,7 +1424,7 @@ final class CoreExtension extends AbstractExtension
public static function batch($items, $size, $fill = null, $preserveKeys = true): array
{
if (!is_iterable($items)) {
throw new RuntimeError(\sprintf('The "batch" filter expects an array or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items)));
throw new RuntimeError(\sprintf('The "batch" filter expects a sequence/mapping or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items)));
}
$size = ceil($size);
@@ -1491,9 +1491,9 @@ final class CoreExtension extends AbstractExtension
$message = \sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object));
} elseif (\is_array($object)) {
if (empty($object)) {
$message = \sprintf('Key "%s" does not exist as the array is empty.', $arrayItem);
$message = \sprintf('Key "%s" does not exist as the sequence/mapping is empty.', $arrayItem);
} else {
$message = \sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object)));
$message = \sprintf('Key "%s" for sequence/mapping with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object)));
}
} elseif (/* Template::ARRAY_CALL */ 'array' === $type) {
if (null === $object) {
@@ -1523,7 +1523,7 @@ final class CoreExtension extends AbstractExtension
if (null === $object) {
$message = \sprintf('Impossible to invoke a method ("%s") on a null variable.', $item);
} elseif (\is_array($object)) {
$message = \sprintf('Impossible to invoke a method ("%s") on an array.', $item);
$message = \sprintf('Impossible to invoke a method ("%s") on a sequence/mapping.', $item);
} else {
$message = \sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
}
@@ -1661,7 +1661,7 @@ final class CoreExtension extends AbstractExtension
if ($array instanceof \Traversable) {
$array = iterator_to_array($array);
} elseif (!\is_array($array)) {
throw new RuntimeError(\sprintf('The column filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array)));
throw new RuntimeError(\sprintf('The column filter only works with sequences/mappings or "Traversable", got "%s" as first argument.', \gettype($array)));
}
return array_column($array, $name, $index);
@@ -1673,7 +1673,7 @@ final class CoreExtension extends AbstractExtension
public static function filter(Environment $env, $array, $arrow)
{
if (!is_iterable($array)) {
throw new RuntimeError(\sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
throw new RuntimeError(\sprintf('The "filter" filter expects a sequence/mapping or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
}
self::checkArrowInSandbox($env, $arrow, 'filter', 'filter');
@@ -1709,7 +1709,7 @@ final class CoreExtension extends AbstractExtension
self::checkArrowInSandbox($env, $arrow, 'reduce', 'filter');
if (!\is_array($array) && !$array instanceof \Traversable) {
throw new RuntimeError(\sprintf('The "reduce" filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array)));
throw new RuntimeError(\sprintf('The "reduce" filter only works with sequences/mappings or "Traversable", got "%s" as first argument.', \gettype($array)));
}
$accumulator = $initial;
+12 -12
View File
@@ -55,9 +55,9 @@ class ExpressionParserTest extends TestCase
}
/**
* @dataProvider getTestsForArray
* @dataProvider getTestsForSequence
*/
public function testArrayExpression($template, $expected)
public function testSequenceExpression($template, $expected)
{
$env = new Environment($this->createMock(LoaderInterface::class), ['cache' => false, 'autoescape' => false]);
$stream = $env->tokenize($source = new Source($template, ''));
@@ -68,9 +68,9 @@ class ExpressionParserTest extends TestCase
}
/**
* @dataProvider getFailingTestsForArray
* @dataProvider getFailingTestsForSequence
*/
public function testArraySyntaxError($template)
public function testSequenceSyntaxError($template)
{
$this->expectException(SyntaxError::class);
@@ -79,7 +79,7 @@ class ExpressionParserTest extends TestCase
$parser->parse($env->tokenize(new Source($template, 'index')));
}
public function getFailingTestsForArray()
public function getFailingTestsForSequence()
{
return [
['{{ [1, "a": "b"] }}'],
@@ -88,10 +88,10 @@ class ExpressionParserTest extends TestCase
];
}
public function getTestsForArray()
public function getTestsForSequence()
{
return [
// simple array
// simple sequence
['{{ [1, 2] }}', new ArrayExpression([
new ConstantExpression(0, 1),
new ConstantExpression(1, 1),
@@ -101,7 +101,7 @@ class ExpressionParserTest extends TestCase
], 1),
],
// array with trailing ,
// sequence with trailing ,
['{{ [1, 2, ] }}', new ArrayExpression([
new ConstantExpression(0, 1),
new ConstantExpression(1, 1),
@@ -131,7 +131,7 @@ class ExpressionParserTest extends TestCase
], 1),
],
// mapping in an array
// mapping in a sequence
['{{ [1, {"a": "b", "b": "c"}] }}', new ArrayExpression([
new ConstantExpression(0, 1),
new ConstantExpression(1, 1),
@@ -147,7 +147,7 @@ class ExpressionParserTest extends TestCase
], 1),
],
// array in a mapping
// sequence in a mapping
['{{ {"a": [1, 2], "b": "c"} }}', new ArrayExpression([
new ConstantExpression('a', 1),
new ArrayExpression([
@@ -168,7 +168,7 @@ class ExpressionParserTest extends TestCase
new NameExpression('b', 1),
], 1)],
// array with spread operator
// sequence with spread operator
['{{ [1, 2, ...foo] }}',
new ArrayExpression([
new ConstantExpression(0, 1),
@@ -301,7 +301,7 @@ class ExpressionParserTest extends TestCase
public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template)
{
$this->expectException(SyntaxError::class);
$this->expectExceptionMessage('A default value for an argument must be a constant (a boolean, a string, a number, or an array) in "index" at line 1');
$this->expectExceptionMessage('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping) in "index" at line 1');
$env = new Environment($this->createMock(LoaderInterface::class), ['cache' => false, 'autoescape' => false]);
$parser = new Parser($env);
@@ -9,4 +9,4 @@ Exception thrown from a child for an extension error
--DATA--
return []
--EXCEPTION--
Twig\Error\RuntimeError: The random function cannot pick from an empty array in "base.twig" at line 4.
Twig\Error\RuntimeError: The random function cannot pick from an empty sequence/mapping in "base.twig" at line 4.
@@ -9,4 +9,4 @@ Exception thrown from an include for an extension error
--DATA--
return []
--EXCEPTION--
Twig\Error\RuntimeError: The random function cannot pick from an empty array in "content.twig" at line 4.
Twig\Error\RuntimeError: The random function cannot pick from an empty sequence/mapping in "content.twig" at line 4.
@@ -5,4 +5,4 @@ Exception for invalid argument type in replace call
--DATA--
return ['stdClass' => new \stdClass()]
--EXCEPTION--
Twig\Error\RuntimeError: The "replace" filter expects an array or "Traversable" as replace values, got "stdClass" in "index.twig" at line 2.
Twig\Error\RuntimeError: The "replace" filter expects a sequence/mapping or "Traversable" as replace values, got "stdClass" in "index.twig" at line 2.
@@ -1,8 +0,0 @@
--TEST--
"cycle" function returns an error on empty arrays
--TEMPLATE--
{{ cycle([], 0) }}
--DATA--
return []
--EXCEPTION--
Twig\Error\RuntimeError: The "cycle" function does not work on empty arrays in "index.twig" at line 2.
+15 -15
View File
@@ -66,17 +66,17 @@ class TemplateTest extends TestCase
return [
['{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1.'],
['{{ null["a"] }}', 'Impossible to access a key ("a") on a null variable in "%s" at line 1.'],
['{{ empty_array["a"] }}', 'Key "a" does not exist as the array is empty in "%s" at line 1.'],
['{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1.'],
['{{ empty_array["a"] }}', 'Key "a" does not exist as the sequence/mapping is empty in "%s" at line 1.'],
['{{ array["a"] }}', 'Key "a" for sequence/mapping with keys "foo" does not exist in "%s" at line 1.'],
['{{ array_access["a"] }}', 'Key "a" in object with ArrayAccess of class "Twig\Tests\TemplateArrayAccessObject" does not exist in "%s" at line 1.'],
['{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1.'],
['{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1.'],
['{{ null.a }}', 'Impossible to access an attribute ("a") on a null variable in "%s" at line 1.'],
['{{ null.a() }}', 'Impossible to invoke a method ("a") on a null variable in "%s" at line 1.'],
['{{ array.a() }}', 'Impossible to invoke a method ("a") on an array in "%s" at line 1.'],
['{{ empty_array.a }}', 'Key "a" does not exist as the array is empty in "%s" at line 1.'],
['{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1.'],
['{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1.'],
['{{ array.a() }}', 'Impossible to invoke a method ("a") on a sequence/mapping in "%s" at line 1.'],
['{{ empty_array.a }}', 'Key "a" does not exist as the sequence/mapping is empty in "%s" at line 1.'],
['{{ array.a }}', 'Key "a" for sequence/mapping with keys "foo" does not exist in "%s" at line 1.'],
['{{ attribute(array, -10) }}', 'Key "-10" for sequence/mapping with keys "foo" does not exist in "%s" at line 1.'],
['{{ array_access.a }}', 'Neither the property "a" nor one of the methods "a()", "geta()"/"isa()"/"hasa()" or "__call()" exist and have public access in class "Twig\Tests\TemplateArrayAccessObject" in "%s" at line 1.'],
['{% from _self import foo %}{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ foo(array_access) }}', 'Neither the property "missing_method" nor one of the methods "missing_method()", "getmissing_method()"/"ismissing_method()"/"hasmissing_method()" or "__call()" exist and have public access in class "Twig\Tests\TemplateArrayAccessObject" in "%s" at line 1.'],
['{{ magic_exception.test }}', 'An exception has been thrown during the rendering of a template ("Hey! Don\'t try to isset me!") in "%s" at line 1.'],
@@ -193,14 +193,14 @@ class TemplateTest extends TestCase
$this->assertSame('IntegerButStringWithLeadingZeros', $array['01']);
$this->assertSame('EmptyString', $array[null]);
$this->assertSame('Zero', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)');
$this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)');
$this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)');
$this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)');
$this->assertSame('MinusOne', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)');
$this->assertSame('FloatButString', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)');
$this->assertSame('IntegerButStringWithLeadingZeros', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)');
$this->assertSame('EmptyString', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, null), 'null is treated as "" when accessing an array (equals PHP behavior)');
$this->assertSame('Zero', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, false), 'false is treated as 0 when accessing a sequence/mapping (equals PHP behavior)');
$this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, true), 'true is treated as 1 when accessing a sequence/mapping (equals PHP behavior)');
$this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, 1.5), 'float is casted to int when accessing a sequence/mapping (equals PHP behavior)');
$this->assertSame('One', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '1'), '"1" is treated as integer 1 when accessing a sequence/mapping (equals PHP behavior)');
$this->assertSame('MinusOne', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, -1.5), 'negative float is casted to int when accessing a sequence/mapping (equals PHP behavior)');
$this->assertSame('FloatButString', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '1.5'), '"1.5" is treated as-is when accessing a sequence/mapping (equals PHP behavior)');
$this->assertSame('IntegerButStringWithLeadingZeros', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, '01'), '"01" is treated as-is when accessing a sequence/mapping (equals PHP behavior)');
$this->assertSame('EmptyString', CoreExtension::getAttribute($twig, $template->getSourceContext(), $array, null), 'null is treated as "" when accessing a sequence/mapping (equals PHP behavior)');
}
/**
@@ -395,7 +395,7 @@ class TemplateTest extends TestCase
$tests = array_merge($tests, [
[false, null, 42, 'a', [], $anyType, 'Impossible to access an attribute ("a") on a integer variable ("42") in "index.twig".'],
[false, null, 'string', 'a', [], $anyType, 'Impossible to access an attribute ("a") on a string variable ("string") in "index.twig".'],
[false, null, [], 'a', [], $anyType, 'Key "a" does not exist as the array is empty in "index.twig".'],
[false, null, [], 'a', [], $anyType, 'Key "a" does not exist as the sequence/mapping is empty in "index.twig".'],
]);
return $tests;