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
 [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

Add a Patch

Pull Requests

Add a Pull Request

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-2024 The PHP Group
All rights reserved.
Last updated: Mon May 06 14:01:33 2024 UTC