Remove reference restrictions from foreach

foreach only allowed variables to be traversed by reference. This never
really made sense because

    a) Expressions like array(&$a, &$b) can be meaningfully iterated by-ref
    b) Function calls can return by-ref (so they can also be meaningfully
       iterated)
    c) Iterators could at least in theory also be iterated by-ref (not
       sure if any iterator makes use of this)

With by-ref generators the restriction makes even less sense, so I removed
it altogether.
This commit is contained in:
Nikita Popov 2012-07-22 14:33:25 +02:00
parent 80748631aa
commit de80e3ce4b
6 changed files with 37 additions and 33 deletions

View File

@ -1,12 +0,0 @@
--TEST--
errmsg: cannot create references to temp array
--FILE--
<?php
foreach (array(1,2,3) as $k=>&$v) {
}
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot create references to elements of a temporary array expression in %s on line %d

View File

@ -0,0 +1,18 @@
--TEST--
Temporary array expressions can be iterated by reference
--FILE--
<?php
$a = 'a';
$b = 'b';
foreach ([&$a, &$b] as &$value) {
$value .= '-foo';
}
var_dump($a, $b);
?>
--EXPECT--
string(5) "a-foo"
string(5) "b-foo"

View File

@ -9,24 +9,34 @@ function &iter(array &$array) {
}
}
$array = [1, 2, 3, 4, 5];
$array = [1, 2, 3];
$iter = iter($array);
foreach ($iter as &$value) {
$value *= -1;
}
var_dump($array);
$array = [1, 2, 3];
foreach (iter($array) as &$value) {
$value *= -1;
}
var_dump($array);
?>
--EXPECT--
array(5) {
array(3) {
[0]=>
int(-1)
[1]=>
int(-2)
[2]=>
int(-3)
[3]=>
int(-4)
[4]=>
&int(-5)
&int(-3)
}
array(3) {
[0]=>
int(-1)
[1]=>
int(-2)
[2]=>
&int(-3)
}

View File

@ -6317,9 +6317,7 @@ void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token
if (value->EA & ZEND_PARSED_REFERENCE_VARIABLE) {
assign_by_ref = 1;
if (!(opline-1)->extended_value) {
zend_error(E_COMPILE_ERROR, "Cannot create references to elements of a temporary array expression");
}
/* Mark extended_value for assign-by-reference */
opline->extended_value |= ZEND_FE_FETCH_BYREF;
CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].extended_value |= ZEND_FE_RESET_REFERENCE;

View File

@ -312,7 +312,7 @@ unticked_statement:
foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); }
| T_FOREACH '(' expr_without_variable T_AS
{ zend_do_foreach_begin(&$1, &$2, &$3, &$4, 0 TSRMLS_CC); }
variable foreach_optional_arg ')' { zend_check_writable_variable(&$6); zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); }
foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); }
foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); }
| T_DECLARE { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); }
| ';' /* empty statement */

View File

@ -1,10 +0,0 @@
--TEST--
Foreach loop tests - error case: reference to constant array, with key.
--FILE--
<?php
foreach (array(1,2) as $k=>&$v) {
var_dump($v);
}
?>
--EXPECTF--
Fatal error: Cannot create references to elements of a temporary array expression in %s on line 2