Skip to content

Commit 3cc1b52

Browse files
committed
Add support for renaming variables in object destructuring
1 parent 09e6bb5 commit 3cc1b52

File tree

4 files changed

+48
-7
lines changed

4 files changed

+48
-7
lines changed

CHANGELOG

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 3.24.0 (2026-XX-XX)
22

3-
* n/a
3+
* Add support for renaming variables in object destructuring (`{name: userName} = user`)
44

55
# 3.23.0 (2026-01-23)
66

doc/templates.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,30 @@ or mapping by extracting values based on property/key names:
11601160
{{ name }} {# user.name #}
11611161
{{ email }} {# user.email #}
11621162
1163+
You can rename variables during destructuring by using the ``key: variable``
1164+
syntax, where the key is the property to extract and the variable is the name
1165+
to assign to:
1166+
1167+
.. code-block:: twig
1168+
1169+
{% do {name: userName, email: userEmail} = user %}
1170+
1171+
{{ userName }} {# user.name #}
1172+
{{ userEmail }} {# user.email #}
1173+
1174+
This is especially useful when you need to destructure multiple objects that
1175+
share the same property names:
1176+
1177+
.. code-block:: twig
1178+
1179+
{% do {data: product, error: productError} = loadProduct() %}
1180+
{% do {data: stock, error: stockError} = loadStock() %}
1181+
1182+
{{ product }} {# loadProduct().data #}
1183+
{{ productError }} {# loadProduct().error #}
1184+
{{ stock }} {# loadStock().data #}
1185+
{{ stockError }} {# loadStock().error #}
1186+
11631187
.. note::
11641188

11651189
Object destructuring uses the :ref:`dot operator <dot_operator>` to access

src/Node/Expression/Binary/ObjectDestructuringSetBinary.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
*/
2424
class ObjectDestructuringSetBinary extends AbstractBinary
2525
{
26-
private array $properties = [];
26+
/** @var list<array{property: string, variable: string}> */
27+
private array $mappings = [];
2728

2829
/**
2930
* @param ArrayExpression $left The array expression containing object/mapping destructuring properties
@@ -38,7 +39,11 @@ public function __construct(Node $left, Node $right, int $lineno)
3839
if (!$pair['value'] instanceof ContextVariable) {
3940
throw new SyntaxError(\sprintf('Cannot assign to "%s", only variables can be assigned in object/mapping destructuring.', $pair['value']::class), $lineno);
4041
}
41-
$this->properties[] = $pair['value']->getAttribute('name');
42+
43+
$this->mappings[] = [
44+
'property' => $pair['key']->getAttribute('value'),
45+
'variable' => $pair['value']->getAttribute('name'),
46+
];
4247
}
4348

4449
parent::__construct($left, $right, $lineno);
@@ -48,18 +53,18 @@ public function compile(Compiler $compiler): void
4853
{
4954
$compiler->addDebugInfo($this);
5055
$compiler->raw('[');
51-
foreach ($this->properties as $i => $property) {
56+
foreach ($this->mappings as $i => $mapping) {
5257
if ($i) {
5358
$compiler->raw(', ');
5459
}
55-
$compiler->raw('$context[')->repr($property)->raw(']');
60+
$compiler->raw('$context[')->repr($mapping['variable'])->raw(']');
5661
}
5762
$compiler->raw('] = [');
58-
foreach ($this->properties as $i => $property) {
63+
foreach ($this->mappings as $i => $mapping) {
5964
if ($i) {
6065
$compiler->raw(', ');
6166
}
62-
$compiler->raw('CoreExtension::getAttribute($this->env, $this->source, ')->subcompile($this->getNode('right'))->raw(', ')->repr($property)->raw(', [], \\Twig\\Template::ANY_CALL, false, false, false, ')->repr($this->getNode('right')->getTemplateLine())->raw(')');
67+
$compiler->raw('CoreExtension::getAttribute($this->env, $this->source, ')->subcompile($this->getNode('right'))->raw(', ')->repr($mapping['property'])->raw(', [], \\Twig\\Template::ANY_CALL, false, false, false, ')->repr($this->getNode('right')->getTemplateLine())->raw(')');
6368
}
6469
$compiler->raw(']');
6570
}

tests/Fixtures/expressions/set.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ Twig supports the "=" operator (assignment)
2121
{% do {name, email} = user %}{{ name }} {{ email }}
2222
{% do {first_name, last_name} = user_map %}{{ first_name }} {{ last_name }}
2323
{% do {name} = user_obj %}{{ name }}
24+
25+
# Object destructuring with renaming
26+
{% do {name: userName, email: userEmail} = user %}{{ userName }} {{ userEmail }}
27+
{% do {first_name: first, last_name: last} = user_map %}{{ first }} {{ last }}
28+
{% do {name: objName} = user_obj %}{{ objName }}
29+
{% do {name: n1} = user %}{% do {name: n2} = user_obj %}{{ n1 }} {{ n2 }}
2430
--DATA--
2531
return [
2632
'user' => (object)['name' => 'Fabien', 'email' => 'fabien@example.com'],
@@ -47,3 +53,9 @@ one two null
4753
Fabien fabien@example.com
4854
Fabien Potencier
4955
Fabien
56+
57+
# Object destructuring with renaming
58+
Fabien fabien@example.com
59+
Fabien Potencier
60+
Fabien
61+
Fabien Fabien

0 commit comments

Comments
 (0)