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 Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: juanparati at gmail dot com
New email:
PHP Version: OS:

 

 [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

Pull Requests

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: Sat Dec 21 14:01:32 2024 UTC