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
T_LIST cannot be used with foreach before.
<?php foreach (array(array(1, 2), array(3, 4)) as list($a, $b)) { /* won't work */ }
It is also a feature request: #10203 allow foreach($array as list($a,$b)
I think this feature could make PHP code more flexible, so I am working on a solution to provide that.
Proposal
1. ZEND_FE_FETCH
<?php foreach (array(array(24,2333), array(31,4666)) 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 foreach (array(array(24,2333), array(31,4666)) 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 */
Opcodes generated:
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
More about RFC
In order to avoid the reduce/reduce conflict, I have to add the new bison rules to the existing “foreach_variable”, which would otherwise bring a side-effect, that is :
considering this script:
<?php foreach (array(1,3,4) as &$key => $foo) { }
before patched:
PHP Parse error: syntax error, unexpected '&', expecting T_STRING or T_VARIABLE or '$' in /home/huixc/test.php on line 2
after patched:
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
Silent Token
about silent token '@', is it neccessary to be supported :
foreach (array(array(1,3,4), array(1, 2)) as @list($a, $b, $c)) { }
if yes, the second patch in the following patchs list can be used.
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 item of array has no index 1*/ }
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
Patchs
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)