Bug #76863 [Com]: Creating array reference grants direct access to the property

From: Date: Tue, 11 Sep 2018 19:21:04 +0000
Subject: Bug #76863 [Com]: Creating array reference grants direct access to the property
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-216990@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=76863&edit=1 ID: 76863 Comment by: spam2 at rhsoft dot net Reported by: tshumbeo at mailhouse dot biz Summary: Creating array reference grants direct access to the property Status: Open Type: Bug Package: Scripting Engine problem Operating System: Linux and Windows PHP Version: 7.2.9 Block user comment: N Private report: N New Comment: > reating a reference *to* an array member (1) should *not* > turn that member into a reference that assumption is simply wrong the golden rule in PHP is not to use references at all until you really know what you are doing, are arwa about all side-effects and are relly sure given the copy-on-write nature of PHP you gain anything below a sample for side-effects of references which i show everyone who thinks references are a god think - don't confuse PHP references with C pointers ---- BAD: <?php $array1 = [1, 2, 3]; $array2 = [5, 6, 7]; foreach($array1 as $key=>&$item) { } foreach($array2 as $key=>$item) { $item = "MY GOD $key"; } print_r($array1); print_r($array2); $item = 'GO AWAY'; print_r($array1); ?> ------- CLEAN BUT USELESS: <?php $array1 = [1, 2, 3]; $array2 = [5, 6, 7]; foreach($array1 as $key=>&$item) { } unset($item); /** FIX */ foreach($array2 as $key=>$item) { $item = "MY GOD $key"; } print_r($array1); print_r($array2); $item = 'GO AWAY'; print_r($array1); ?> Previous Comments: ------------------------------------------------------------------------ [2018-09-11 19:14:16] tshumbeo at mailhouse dot biz Description: ------------ Tested on PHP 5.6.37 and 7.2.9, Windows and Linux, various configurations. See the test script. When (1) is present (assignment by reference) and (2) is missing (no unsetting), it appears that K->$a[0] itself becomes a reference (not $unusedVariable, which would be expected). When K->a() - a typical read accessor method - returns the array, modifying the array's member affects the K->$a. If (2) is present, then the $a[0] reference is removed and it's no more possible to change the K->$a by changing K->a() members. (1) | (2) | Result ----|-------|------- & | unset | no bug | unset | no bug | | no bug & | | bug! A practical consequence: I am unable to create a reference to the internal array's members (for use in other places) without opening doors to direct modification of the property which can happen inadvertently (this is how I stumbled upon it): function clean(array $ar) { foreach ($ar as &$ref) $ref = ...; return $ar; } clean($k->a()); Do note that clean() doesn't accept $a by reference, it simply uses it as a copy for returning in the result. However, due to the bug it in fact directly modifies $k's internal $a array! Test script: --------------- class K { private $a = ['a']; function a() { return $this->a; } function f($f) { // (1) $unusedVariable = &$this->a[0]; // (2) //unset($unusedVariable); $f(); } } $k = new K; $k->f(function () use ($k) { foreach ($k->a() as &$ref) { $ref = 123; } }); // Expected result: string 'a'. // Actual result: int 123. var_dump($k->a()); Expected result: ---------------- Creating a reference *to* an array member (1) should *not* turn that member into a reference (to itself?). Actual result: -------------- Creating a reference turns that member into a sticky reference that isn't removed by array cloning functions like array_values(), array_merge(), unset(), etc. and can be removed only by unsetting (2) the referencing variable (even if it's out of scope the reference remains). ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=76863&edit=1

« previous php.bugs (#216990) next »