php.net |  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
Description:
------------
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:
----------------
2,4,6,

Actual result:
--------------
2,4,4,

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-11-19 22:32 UTC] rasmus@php.net
-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] aharvey@php.net
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] yohgaki@php.net
I'm missing something probably, but this result is interesting to me.

http://3v4l.org/G2fXg
http://3v4l.org/CCadi

I don't have time to look into now :)
 [2014-11-20 01:20 UTC] yohgaki@php.net
I got it. I works as it documented ;)

http://3v4l.org/eH1NY
 [2014-11-20 01:27 UTC] yohgaki@php.net
Sample code in the doc may be improved.
I didn't understand what's going on at first.

http://3v4l.org/jNfvt

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

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

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

http://3v4l.org/QSZXm

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] yohgaki@php.net
http://3v4l.org/ui7LJ
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] rasmus@php.net
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] yohgaki@php.net
@rasmus I agree. We are better to stay in the basic principle.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 18 20:01:30 2024 UTC