|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
[2001-05-23 18:49 UTC] jeroen@php.net
[2001-11-22 18:24 UTC] venaas@php.net
[2001-12-12 08:12 UTC] yohgaki@php.net
[2002-02-11 03:18 UTC] nassar at wpi dot edu
[2002-06-24 23:43 UTC] pkeshish at idontlike dot spam dot yahoo dot com
[2002-08-22 11:18 UTC] iliaa@php.net
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Nov 06 04:00:02 2025 UTC |
<?php /* I've discovered some slightly counter-intuitive behaviour with references and arrays. I'm not sure whether this is actually a bug or a 'feature', but if it is the latter then it should be documented as such. Consider the following code involving references and integers: */ $a = 5; $b = &$a; $c = $a; $c = 10; echo "(1) a: $a (should be 5)<br>\n"; /* Here we have created a variable ($a), made a reference to it ($b), made a copy of the original variable ($c), changed the copy ($c=10), and then printed out the original value. This is all fine and as expected. Now let's try the same thing, but with the addition of arrays: */ $A = array(); $A[0] = 5; $b = &$A[0]; $C = $A; $C[0] = 10; echo "(2) A[0]: $A[0] (I expected it to be 5)<br>\n"; /* Thus, having copied the array $A to $C, we have actually made $C[0] *another* reference to the $A[0] (which is also referenced by $c). I would have expected $C[0] to have become detached from the reference (as in $c = $a in the first example). Taking out the line '$b = &$A[0]' in the example above yields the expected behaviour: */ $A = array(); $A[0] = 5; $C = $A; $C[0] = 10; echo "(3) A[0]: $A[0] (expected it to actually be 5 this time)<br>\n"; /* Q: What's the explanation for all of this? A: When the Zend Engine constructs a copy of an array/hash, it constructs copies of the individual elements by using zval_add_ref (zend_variables.c). This simply increases the reference count of the value in question. If that value happens to be referenced by more than one name, it has the 'is_ref' flag set. However, in the case of copying array elements, the values are still _not_ separated if they have 'is_ref' set. As I mentioned above, I'm not sure whether this is actually the desired behaviour or not. In either case, I couldn't find it documented clearly anywhere (maybe I didn't look hard enough--if not, sorry in advance!). Working under the assumption that the behaviour is incorrect (I certainly find it very confusing), I worked out the following fix to the issue (assuming my understanding of the Zend Engine is correct): Instead of using zval_add_ref as the constructor when copying arrays, use this: ZEND_API void zval_add_ref_or_separate(zval **p) { if (PZVAL_IS_REF(*p)) { SEPARATE_ZVAL(p); } else { zval_add_ref(p); } } Another question is whether there are similar issues with objects? I haven't investigated... Note: I haven't included PHP modules/php.ini etc since I'm fairly sure this issue is unrelated to any site-specific setup. */ ?>