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)