php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68914 Reference survives beyond function scope
Submitted: 2015-01-26 05:23 UTC Modified: 2015-01-26 21:17 UTC
From: steve dot piner at signify dot co dot nz Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 5.6.5 OS: Ubuntu 14.10
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: steve dot piner at signify dot co dot nz
New email:
PHP Version: OS:

 

 [2015-01-26 05:23 UTC] steve dot piner at signify dot co dot nz
Description:
------------
A reference created with a foreach loop appears to survive long after the function creating the reference has exited.

Test script:
---------------
function f() {
  static $x;
  if(!$x) {
    $x = range(1, 3);
  }
  foreach($x as $i => &$j) { }
  return $x;
}
$z = f();
$y = f();
$y[2] = 'surprise';
print $z[2] . "\n";

Expected result:
----------------
3


Actual result:
--------------
surprise


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-01-26 07:00 UTC] requinix@php.net
-Status: Open +Status: Not a bug -Package: PHP Language Specification +Package: Scripting Engine problem
 [2015-01-26 07:00 UTC] requinix@php.net
It survives because $x is static and each member in $x is a reference.

$x was initialized once to that range(1,3) array. Whenever f() returns it will return a copy of that array, thus $z and $y have both the same array values even though they are different actual arrays.
Modifying $y would have no effect on $z because of the copying... if it weren't for the by-ref foreach you did, which caused each member in the array to become a reference. That makes $x[2], $y[2], and $z[2] all the same so a change made to one of them will "appear" in the others.
 [2015-01-26 20:52 UTC] steve dot piner at signify dot co dot nz
The point isn't that $x survives, the point is that only the last element is a reference, and that it wasn't explicitly converted to a reference.

Set $y[1] to 'surprise' and then print out $z[1]: you'll get a result of 2.

Only the last element of $x is a reference after the foreach() has exited.

The bug is that the last element remains a reference after the referencing variable ($j) has for all intents and purposes ceased to exist.

For example, if you add an unset($j); after the foreach(), the issue disappears.
 [2015-01-26 21:17 UTC] requinix@php.net
Poor phrasing on my part: each element *was* a reference, and when the loop moves to the next element the previous is destroyed. At the end the last element remains a reference.

However I'm also going along with previous decisions, such as bug #68402, which say that this behavior is not a bug. References can be tricky and unset()ing referenced variables when you're done with them is a good idea.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Tue Jul 01 13:01:35 2025 UTC