PHP 4.0 Bug #6417: Possibly incorrect behaviour with references and arrays
| From: | jon at imagenet dot co dot uk | Date: | Tue, 29 Aug 2000 16:17:34 +0000 |
| Subject: | PHP 4.0 Bug #6417: Possibly incorrect behaviour with references and arrays | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-31088@lists.php.net to get a copy of this message | ||
From: jon@imagenet.co.uk
Operating system: Linux RedHat 6.2
PHP version: 4.0.1pl2
PHP Bug Type: Scripting Engine problem
Bug description: Possibly incorrect behaviour with references and arrays
<?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.
*/
?>