This is an old revision of the document!
RFC: foreach_variable supporting T_LIST
- Version: 1.0
- Date: 2011-07-06
- Author: Xinchen Hui laruence@php.net
- Status: Under Discussion
- First Published at: http://wiki.php.net/rfc/foreachlist/
Introduction
This feature introduces list() support in foreach constructs:
<?php $users = array( array('Foo', 'Bar'), array('Baz', 'Qux'); ); // Before foreach ($users as $user) { list($firstName, $lastName) = $user; echo "First name: $firstName, last name: $lastName. "; } // After foreach ($users as list($firstName, $lastName)) { echo "First name: $firstName, last name: $lastName. "; }
This feature eliminates the use of a redundant variable ($user in the example above), reduces code verbosity in typical cases of iterating structured data, such as SQL result sets, and it doesn't introduce new keywords, but simply reuses a familiar PHP construct in a new context.
It's a commonly requested feature, and there is evidence that people already expect list() should work in this scenario: #10203 allow foreach($array as list($a,$b)
This RFC provides a behavior specification and implementation for this feature.
Proposal
1. ZEND_FE_FETCH
<?php $rows = array(array(24,2333), array(31,4666)); foreach ($rows as list($a, $b)) { printf("a=>%s, b=>%s\n", $a, $b); } /** Output: a=>24, b=>2333 a=>31, b=>4666 */
2. ZEND_FE_FETCH_WITH_KEY
<?php $rows = array(array(24,2333), array(31,4666)); foreach ($rows as $k => list($a, $b)) { printf("key:%s, a=>%s, b=>%s\n", $k, $a, $b); } /** Output: key:0, a=>24, b=>2333 key:1, a=>31, b=>4666 */
Samples with generated opcodes:
list.php
<?php foreach (array(array(1, 2), array(3, 4)) as list($a, $b)) { echo $a, $b; }
2 0 > INIT_ARRAY ~0 1
1 ADD_ARRAY_ELEMENT ~0 2
2 INIT_ARRAY ~1 ~0
3 INIT_ARRAY ~2 3
4 ADD_ARRAY_ELEMENT ~2 4
5 ADD_ARRAY_ELEMENT ~1 ~2
6 > FE_RESET $3 ~1, ->16
7 > > FE_FETCH $4 $3, ->16
8 > ZEND_OP_DATA
9 FETCH_DIM_R $5 $4, 1
10 ASSIGN !1, $5
11 FETCH_DIM_R $7 $4, 0
12 ASSIGN !0, $7
3 13 ECHO !0
14 ECHO !1
4 15 > JMP ->7
16 > SWITCH_FREE $3 1 1
list_with_key.php
<?php $array = array( array(1, 2), array(3, 4) ); foreach ($array as $k => list($a, $b)) { echo $k, $a, $b; }
3 0 > INIT_ARRAY ~0 1
1 ADD_ARRAY_ELEMENT ~0 2
2 INIT_ARRAY ~1 ~0
4 3 INIT_ARRAY ~2 3
4 ADD_ARRAY_ELEMENT ~2 4
5 5 ADD_ARRAY_ELEMENT ~1 ~2
6 ASSIGN !0, ~1
7 7 > FE_RESET $4 !0, ->19
8 > > FE_FETCH $5 $4, ->19
9 > ZEND_OP_DATA ~10
10 FETCH_DIM_R $6 $5, 1
11 ASSIGN !3, $6
12 FETCH_DIM_R $8 $5, 0
13 ASSIGN !2, $8
14 ASSIGN !1, ~10
8 15 ECHO !1
16 ECHO !2
17 ECHO !3
9 18 > JMP ->8
19 > SWITCH_FREE $4
10 20 > RETURN 1
Implementation details of the RFC
In order to avoid the reduce/reduce conflict, new bison rules will be added to the existing “foreach_variable”, to avoid this side effect:
<?php foreach (array(1,3,4) as &$key => $foo) { }
Without the rules:
PHP Parse error: syntax error, unexpected '&', expecting T_STRING or T_VARIABLE or '$' in /home/huixc/test.php on line 2
With the rules:
PHP Fatal error: Key element cannot be a reference in /home/huixc/test.php on line 2 Fatal error: Key element cannot be a reference in /home/huixc/test.php on line 2
Possible additional features (vote separately): silent token
It is possible to add support of the silent token in the new context:
foreach (array(array(1,3,4), array(1, 2)) as @list($a, $b, $c)) { }
In case we want this, an additional patch will be provided.
Opcodes generated:
list_with_silent.php
<?php foreach (array(array(1, 2), array(3, 4), array(5)) as @list($a, $b)) { echo $a, $b; // Without the silent token, there will be a notice since the third nested array has no second item. }
2 0 > INIT_ARRAY ~0 1
1 ADD_ARRAY_ELEMENT ~0 2
2 INIT_ARRAY ~1 ~0
3 INIT_ARRAY ~2 3
4 ADD_ARRAY_ELEMENT ~2 4
5 ADD_ARRAY_ELEMENT ~1 ~2
6 INIT_ARRAY ~3 5
7 ADD_ARRAY_ELEMENT ~1 ~3
8 > FE_RESET $4 ~1, ->22
9 > > FE_FETCH $5 $4, ->22
10 > ZEND_OP_DATA
11 BEGIN_SILENCE ~6
12 FETCH_DIM_R $9 $5, 1
13 FETCH_W local $8 'b'
14 ASSIGN $8, $9
15 FETCH_DIM_R $11 $5, 0
16 FETCH_W local $7 'a'
17 ASSIGN $7, $11
18 END_SILENCE ~6
3 19 ECHO !0
20 ECHO !1
4 21 > JMP ->9
22 > SWITCH_FREE $4
5 23 > RETURN 1
Patches
Tests
Changelog
- 2011-07-06 Xinchen Hui: Initial RFC creation
- 2011-07-06 Xinchen Hui: Updated patch
- 2011-07-06 Xinchen Hui: Added tests phpt
- 2011-07-07 Xinchen Hui: Added supporting for slience token(@)
- 2011-07-07 Xinchen Hui: Updated sencode patch
- 2011-07-08 Xinchen Hui: Added opcodes with silent token
- 2011-07-24 Xinchen Hui: Updated patches that fixed a bug: znode->EA may be depend on an uninitialized value (thanks to Felipe)
- 2012-07-18 Phidev: Rewrote the RFC