php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #80541 foreach by-val vs. by-ref traversal unclear
Submitted: 2020-12-22 09:54 UTC Modified: 2021-07-20 09:48 UTC
From: andre at webkr dot de Assigned:
Status: Verified Package: Arrays related
PHP Version: 8.0.0 OS:
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please — but make sure to vote on the bug!
Your email address:
MUST BE VALID
Solve the problem:
40 + 8 = ?
Subscribe to this entry?

 
 [2020-12-22 09:54 UTC] andre at webkr dot de
Description:
------------
I'm not sure whether this is a bug or a documentation bug. I'd consider it a bug but given the promise of backwards compatibility it's unlikely to be fixed.

If the iterator variable in a foreach is a reference, then the whole array becomes a reference and it is no longer safe to append to the array. This is true even when the iterator variable is not actually used anywhere.

At least this behavior should be documented. The documentation currently says:

> In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.

It says nothing about the array itself, only about the array values, reenforcing the wrong impression that it is still safe to add or remove array elements.

Test script:
---------------
$arr = ['a','b','c'];

foreach ($arr as &$dummy)
{
    $arr []= 'foo';
}

var_dump($arr);

Expected result:
----------------
array(6) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
  [3]=>
  string(3) "foo"
  [4]=>
  string(3) "foo"
  [5]=>
  string(3) "foo"
}

Actual result:
--------------
Fatal error: Allowed memory size of [...] bytes exhausted

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-05-24 00:20 UTC] a3ron223 at gmail dot com
The foreach function will continue to run until it has reached the end of the array.
If the foreach function adds another key to the array every time it runs, then it will not stop running (until it exhausts the script's memory).

I'm a little surprised that it isn't documented.
 [2021-07-20 09:48 UTC] cmb@php.net
-Summary: Using a reference as iterator variable turns the whole array into a reference +Summary: foreach by-val vs. by-ref traversal unclear -Status: Open +Status: Verified
 [2021-07-20 09:48 UTC] cmb@php.net
This not related to the fact that $arr is turned into a
reference[1], but rather that foreach by-val traversal actually
happens on a (separated) copy of the original array[2], while
by-ref traversal happens on the original array.

This is by design, so, yes, documentation issue.

[1] <https://3v4l.org/DuEcf>
[2] <https://3v4l.org/8LL0C>
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Sat Jul 31 02:01:23 2021 UTC