rfc:foreachlist

This is an old revision of the document!


RFC: foreach_variable supporting T_LIST

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)
rfc/foreachlist.1324257655.txt.gz · Last modified: 2017/09/22 13:28 (external edit)