Alex Rivera | Logout

Playing with references

Asked 2013-05-20T23:43:02.430
19

I can see why

$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$c['ID'] = 37;
echo $a['ID']."\n";
echo $b."\n";
echo $c['ID']."\n";

outputs 37, 42, 37

while

$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$b = 37;
echo $a['ID']."\n";
echo $b."\n";
echo $c['ID']."\n";

outputs 37, 37, 37

In both cases $b is a reference to $a['ID'] while $c is a pointer to the same object as $a.

When $b changes $a['ID'] and $c['ID'] change because assigning $b changes the value referenced by $a['ID'].

When $c['ID'] changes, a new int is assigned to $a['ID'], $b doesn't reference $a['ID'] anymore.

But this itches me

$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$c['ID'] &= 0;
$c['ID'] |= 37;
echo $a['ID']."\n";
echo $b."\n";
echo $c['ID']."\n";

(outputs 37, 37, 37)

Is this defined behaviour? I didn't see anything about that in the documentation...

Edit
Report

1 Answer

2

It's more or less defined (but sometimes undocumented) behaviour; mainly because $a is not an array but an ArrayObject.

Let's take a look at your third code fragment first:

$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$c['ID'] &= 0;

The last assignment translates to:

$tmp = &$c->offsetGet('ID');
$tmp &= 0; // or: $tmp = $tmp & 0;

The take-away point here is only offsetGet() is called and it returns a reference to $c['ID'], as noted in this comment. Because offsetSet() is not called, the value of $b changes as well.

Btw, the increment (++) and decrement operator (--) work in a similar fashion, no offsetSet() is called.

Differences

This is different from your first example:

$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$c['ID'] = 37;

The last statement has the following equivalent:

$c->offsetSet('ID', 37);

Before a new value is assigned to $c['ID'], the previous value is effectively unset(); this is why $b is the only variable still holding on to 42.

Proof of this behaviour can be seen when you use objects instead of numbers:

class MyLoggerObj
{
        public function __destruct()
        {
                echo "Destruct of " . __CLASS__ . "\n";
        }
}

$a = new ArrayObject();
$a['ID'] = new MyLoggerObj();
$a['ID'] = 37;

echo $a['ID']."\n";

Output:


                        
                        
answered 2013-05-22T09:32:41.317

Your Answer