|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #68457 Reference by pointer inaccurate in foreach
Submitted: 2014-11-19 22:28 UTC Modified: 2014-11-21 03:03 UTC
From: mberding at dtoolbox dot com Assigned:
Status: Not a bug Package: Variables related
PHP Version: 5.4.35 OS: CentOS
Private report: No CVE-ID: None
 [2014-11-19 22:28 UTC] mberding at dtoolbox dot com
In the code below the last element in the $a array is replaced with a copy of the second-to-last element.

Tested and confirmed in PHP versions: 5.3.3, 5.4.34, 5.6.2

Tested OS: CentOS 6.5, 7

Test script:
//Test Script:

$a = array(1,2,3);

foreach($a AS &$y) {
     $y = $y*2;

foreach($a AS $y) {
     echo $y.', ';

Expected result:

Actual result:


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2014-11-19 22:32 UTC]
-Status: Open +Status: Not a bug
 [2014-11-19 22:50 UTC] mberding at dtoolbox dot com
-Type: Bug +Type: Documentation Problem
 [2014-11-19 22:50 UTC] mberding at dtoolbox dot com
If it's not considered a bug, then the documentation should at least be updated to state that the foreach method does not initiate a new variable for the value variable instead of saying, "Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset()."

Simply stating that it still exists doesn't also imply that foreach will not use a new variable when the same variable name is used in a new foreach loop.
 [2014-11-19 23:00 UTC]
PHP doesn't have block scope in general, so I'm not sure why it would be expected that $y would be bound to the scope of the foreach loop in any way.

I'm not really inclined to change the text on the foreach page yet again, honestly — it's been through so many revisions at this point that it's getting a little silly, and this variant seems to have generated fewer bug reports than the previous ones.
 [2014-11-19 23:15 UTC]
I'm missing something probably, but this result is interesting to me.

I don't have time to look into now :)
 [2014-11-20 01:20 UTC]
I got it. I works as it documented ;)
 [2014-11-20 01:27 UTC]
Sample code in the doc may be improved.
I didn't understand what's going on at first.

$a = array(1,2,3,4);

foreach($a AS &$y) {
     $y = $y*2;
echo PHP_EOL;

foreach($a AS $y) {
     echo $y.' ';
echo PHP_EOL;
 [2014-11-20 01:35 UTC]
Or is it possible not to change the last element of the input array a reference?
It would be the best behavior.

According this result, all elements became reference until 5.2.0 which is consistent for elements. Current behavior is inconsistent, it seems.
 [2014-11-20 01:42 UTC]
The last element became usual var with unset(), though. Separate zval after foreach by default, parhaps?
 [2014-11-20 02:07 UTC] gabri dot ns at gmail dot com
there is nothing wrong with foreach documentation, it is @mberding lack of understanding of reference that cause this, and i think it is because reference documentation where placed far below.

since reference is about variable, why don't place it right after?
i think its a good thing.
 [2014-11-20 02:24 UTC]
yohgaki, there is absolutely nothing wrong here. As Adam said, there is no block-scope in PHP and we shouldn't in any way mangle variables in loops. The original code in this report is exactly equivalent to:

$a = array(1,2,3);
// First loop
$y = &$a[0];
$y = $y * 2;
$y = &$a[1];
$y = $y * 2;
$y = &$a[2];
$y = $y * 2;
// Second loop
$y = $a[0];
echo $y.', ';
$y = $a[1];
echo $y.', ';
$y = $a[2];
echo $y.', ';

Simply unrolling the loops here. $y must be a reference to $a[2] at the start of the second loop because that is what the code says to do. If we artificially try to separate that reference all sorts of code that is written to use references correctly will break.
 [2014-11-21 03:03 UTC]
@rasmus I agree. We are better to stay in the basic principle.
PHP Copyright © 2001-2023 The PHP Group
All rights reserved.
Last updated: Sat Dec 09 08:01:29 2023 UTC