php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79264 Value assigned by reference in foreach is do not overwrite to removed variable
Submitted: 2020-02-12 10:18 UTC Modified: 2020-02-12 10:33 UTC
From: juanparati at gmail dot com Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 7.3.14 OS: Linux
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 !
Your email address:
MUST BE VALID
Solve the problem:
27 + 41 = ?
Subscribe to this entry?

 
 [2020-02-12 10:18 UTC] juanparati at gmail dot com
Description:
------------
It's very well documented that behaviour of variables passed by reference into a foreach can have unexpected behaviours when the variables were previosly used.

From PHP documentation:
"Warning

Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset(). Otherwise you will experience the following behavior"

However I found that in some cases even when the variable used as reference is previously removed using "unset" the issue persist.

I can reproduce this issue from PHP 5.6 TO PHP 7.4 with the same result.

It seems that if variables previously are removed (unset) and used again as reference into the foreach can have a wrong behaviour.

This issue is probably due the way that PHP keep the internal references.



Test script:
---------------
See the following code
https://3v4l.org/h6d0G

The array subnodes "needle" and "haystack" were automatically appended for the first element of the array even if the variable used as reference was previously removed (unset).

In the following example the result is the expected one when the variables were not previously used:
https://3v4l.org/4kRmH 



Expected result:
----------------
array(2) {
  ["18427e904f7a227e8c3b80dd2858a70e"]=>
  array(2) {
    ["needle"]=>
    array(1) {
      [0]=>
      array(3) {
        ["starts_at"]=>
        int(11821)
        ["ends_at"]=>
        int(14377)
        ["length"]=>
        int(2556)
      }
    }
    ["haystack"]=>
    array(1) {
      [0]=>
      array(4) {
        ["starts_at"]=>
        int(12227)
        ["ends_at"]=>
        int(14783)
        ["length"]=>
        int(2556)
        ["original"]=>
        string(3) "foo"
      }
    }
  }
  ["dd0c26f35ebf55de25eabea3edbfba32"]=>
  array(2) {
    ["needle"]=>
    array(1) {
      [0]=>
      array(3) {
        ["starts_at"]=>
        int(17255)
        ["ends_at"]=>
        int(32431)
        ["length"]=>
        int(15176)
      }
    }
    ["haystack"]=>
    array(1) {
      [0]=>
      array(4) {
        ["starts_at"]=>
        int(17776)
        ["ends_at"]=>
        int(33032)
        ["length"]=>
        int(15256)
        ["original"]=>
        string(3) "foo"
      }
    }
  }
}


Actual result:
--------------
array(2) {
  ["18427e904f7a227e8c3b80dd2858a70e"]=>
  array(2) {
    ["needle"]=>
    array(1) {
      [0]=>
      array(1) {
        [0]=>
        array(4) {
          ["starts_at"]=>
          int(17255)
          ["ends_at"]=>
          int(32431)
          ["length"]=>
          int(15176)
          ["original"]=>
          string(3) "foo"
        }
      }
    }
    ["haystack"]=>
    array(1) {
      [0]=>
      array(1) {
        [0]=>
        array(4) {
          ["starts_at"]=>
          int(17776)
          ["ends_at"]=>
          int(33032)
          ["length"]=>
          int(15256)
          ["original"]=>
          string(3) "foo"
        }
      }
    }
  }
  ["dd0c26f35ebf55de25eabea3edbfba32"]=>
  array(2) {
    ["needle"]=>
    array(1) {
      [0]=>
      array(3) {
        ["starts_at"]=>
        int(17255)
        ["ends_at"]=>
        int(32431)
        ["length"]=>
        int(15176)
      }
    }
    ["haystack"]=>
    array(1) {
      [0]=>
      array(3) {
        ["starts_at"]=>
        int(17776)
        ["ends_at"]=>
        int(33032)
        ["length"]=>
        int(15256)
      }
    }
  }
}

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-02-12 10:33 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2020-02-12 10:33 UTC] nikic@php.net
You need to unset *after* the loop, not *before* it. Otherwise the (still referenced) variables are going to be used in the following code (in this case the preceding code, because you have an outer loop).
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 11:01:28 2024 UTC