php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73622 Foreach iteration with a previously initialized variable
Submitted: 2016-11-30 09:09 UTC Modified: 2016-12-01 13:13 UTC
From: dorin dot marcoci at gmail dot com Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 7.0.13 OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: dorin dot marcoci at gmail dot com
New email:
PHP Version: OS:

 

 [2016-11-30 09:09 UTC] dorin dot marcoci at gmail dot com
Description:
------------
Script below output A A instead of A B.
Is this as designed?

If I do unset($Item) before second foreach then it works as expected.

Test script:
---------------
<?php

$Items = [['Code' => 'A'], ['Item' => 'B']];

foreach ($Items as &$Item)
    $Item['Hash'] = rand(1, 10);

foreach ($Items as $Item)
    echo ' '.$Item['Code'];


Expected result:
----------------
A B

Actual result:
--------------
A A

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-11-30 09:12 UTC] requinix@php.net
-Status: Open +Status: Not a bug -Package: PHP Language Specification +Package: Scripting Engine problem
 [2016-11-30 09:12 UTC] requinix@php.net
Please take note of the big red warning in the documentation.
http://php.net/manual/en/control-structures.foreach.php
 [2016-11-30 09:24 UTC] dorin dot marcoci at gmail dot com
OK, big red warning is not an excuse. This IS definitely a bug.

When I do foreach($Array AS $VAR) then it should return in var a NEW $VAR instance  in any way, was it used previously or not.
 [2016-12-01 07:22 UTC] a at b dot c dot de
So you want variable references in this particular instance to behave differently from the way they behave in the rest of the language? Not gonna happen.
 [2016-12-01 13:13 UTC] dorin dot marcoci at gmail dot com
The problem is that foreach performs differently.

This script:

<?php

$A = new stdClass();
$A->Code = 'one';

$B = new stdClass();
$B->Code = 'two';

$H = [$A, $B];
$C = &$A;

foreach ($H as $C) 
	echo ' '.$C->Code;

?>

Outputs: " one two", even if $C initially was a reference.

BUT this one:

<?php

$A = new stdClass();
$A->Code = 'one';

$B = new stdClass();
$B->Code = 'two';

$H = [$A, $B];

foreach ($H as &$C);

foreach ($H as $C) 
	echo ' '.$C->Code;

?>

Outputs: " one one", Surprise!.
 [2016-12-20 07:54 UTC] a at b dot c dot de
<?php

$A = 'one';

$B = 'two';

$H = [$A, $B];

 foreach ($H as &$C);

foreach ($H as $C) 
echo ' '.$C;

echo "\n$A $B\n" . join(" ", $H);

?>
Is equivalent to
<?php

$A = 'one';

$B = 'two';

$H = [$A, $B];

for($i = 0; $i < count($H); $i++)
{
 $C = &$H[$i];
}

for($i = 0; $i < count($H); $i++)
{
	$C = $H[$i];
	echo ' '.$C;
}

echo "\n$A $B\n" . join(" ", $H);
?>

And is therefore equivalent to:

<?php

$A = 'one';

$B = 'two';

$H = [$A, $B];

$C = &$H[0];
$C = &$H[1];

$C = $H[0];
echo ' '.$C;
$C = $H[1];
echo ' '.$C;

echo "\n$A $B\n" . join(" ", $H);
?>

So with "$C = &$H[1];" $C is set as a reference to the 1st element of H. Then the value of the 0th element of $H is assigned to it (and therefore, by reference, the 1st element of $H). Then the 1st element of $H (which now has the same value as the 0th element) is assigned to it (which has no effect because the 1st element of H already has the same value as the 1st element of H).
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sat Jul 05 04:01:35 2025 UTC