Bug #80826 [Com]: Array member reference affecting pass by value assignment
| From: | tshumbeo at mailhouse dot biz | Date: | Thu, 04 Mar 2021 08:49:42 +0000 |
| Subject: | Bug #80826 [Com]: Array member reference affecting pass by value assignment | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-232529@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=80826&edit=1
ID: 80826
Comment by: tshumbeo at mailhouse dot biz
Reported by: tshumbeo at mailhouse dot biz
Summary: Array member reference affecting pass by value
assignment
Status: Not a bug
Type: Bug
Package: *General Issues
Operating System: Windows & Linux
PHP Version: 7.4.15
Block user comment: N
Private report: N
New Comment:
> And when $a is copied into the f() function, its $a[2] is a copy *of the reference*.
I understand now. Thanks. This can happen without foreach:
<?php
$a = [1, 2, 3];
$a[1] = &$x;
// $a[1] is &NULL
f($a);
// $a[1] is now &array(NULL)
?>
Perhaps this case should be mentioned not only in foreach's documentation (where it's not
obvious at all) but in one on parameter passing or references? This doesn't have anything to do
with foreach after all.
Previous Comments:
------------------------------------------------------------------------
[2021-03-04 08:28:42] requinix@php.net
> In other words, there is an implicit $reference = <next array member>;
> assignment in loop 2.
No. You missed an important part in the note's first sentence:
> Reference of a $value and the last array element remain even after the foreach
> loop.
*The last element is also a reference*.
In your code, that means $reference *and* $a[2] are references. And when $a is copied into the f()
function, its $a[2] is a copy *of the reference*.
------------------------------------------------------------------------
[2021-03-04 07:36:41] tshumbeo at mailhouse dot biz
Please read the test script carefully. The documentation says about this case:
foreach ($array as &$reference) { ... }
// followed by:
foreach ($array as $reference) { ... }
In other words, there is an implicit $reference = <next array member>; assignment in loop 2.
However, in my case there is no such assignment: the array is passed into the function via parameter
that IS NOT a reference:
foreach ($array as &$reference) { ... }
f($array);
Moreover, inside f() there are no references either and yet the outer $reference somehow affects how
f() assigns array members (which must be a copy!).
How can you explain this?
------------------------------------------------------------------------
[2021-03-03 21:00:00] requinix@php.net
There is a big red note in foreach's documentation about this.
------------------------------------------------------------------------
[2021-03-03 19:46:30] tshumbeo at mailhouse dot biz
Description:
------------
See the test script. When (1) is not present (leaving the member reference in the outside scope when
f() is called), the assignment inside f() is able to modify the passed array even though it
doesn't accept it by reference (note "&array(1)" in Actual Result). Removing the
reference explicitly with (1) avoids this problem.
Test script:
---------------
<?php
$a = [1, 2, 3];
foreach ($a as &$reference) {
$reference = (object) ['x' => $reference];
}
// (1)
//unset($reference);
f($a);
var_dump($a);
function f($a) {
foreach ($a as $k => $v) {
$a[$k] = [$v];
}
}
Expected result:
----------------
array(3) {
[0]=>
object(stdClass)#1 (1) {
["x"]=>
int(1)
}
[1]=>
object(stdClass)#2 (1) {
["x"]=>
int(2)
}
[2]=>
object(stdClass)#3 (1) {
["x"]=>
int(3)
}
}
Actual result:
--------------
array(3) {
[0]=>
object(stdClass)#1 (1) {
["x"]=>
int(1)
}
[1]=>
object(stdClass)#2 (1) {
["x"]=>
int(2)
}
[2]=>
&array(1) { // !!!
[0]=>
object(stdClass)#3 (1) {
["x"]=>
int(3)
}
}
}
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=80826&edit=1