class a {
public $test="msg1";
}
$t1 = new a;
echo "echo1: After Instantiation :<br/>";
xdebug_debug_zval('t1');echo "<br/><br/>";
$t2 = $t1;
echo 'echo2: After assigning $t1 to $t2 :<br/>';
xdebug_debug_zval('t2');echo "<br/><br/>";
$t1->test="msg2";
echo 'echo3: After assigning $t1->test = "msg2" :<br/>';
xdebug_debug_zval('t1');echo "<br/>";
xdebug_debug_zval('t2');echo "<br/><br/>";
$t2->test="msg3";
echo 'echo4: After assigning $t2->test="msg3" :<br/>';
xdebug_debug_zval('t1');echo "<br/>";
xdebug_debug_zval('t2');echo "<br/><br/>";
$t2->test2 = "c*ap!";
echo 'echo5: After injecting $test2 to $t2 :<br/>';
xdebug_debug_zval('t1');echo "<br/>";
xdebug_debug_zval('t2');echo "<br/><br/>";
The output:
echo1: After Instantiation :
t1: (refcount=1, is_ref=0)=class a { public $test = (refcount=2, is_ref=0)=’msg1′ }echo2: After assigning $t1 to $t2 :
t2: (refcount=2, is_ref=0)=class a { public $test = (refcount=2, is_ref=0)=’msg1′ }echo3: After assigning $t1->test = “msg2” :
t1: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg2′ }
t2: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg2′ }echo4: After assigning $t2->test=”msg3″ :
t1: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg3′ }
t2: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg3′ }echo5: After injecting $test2 to $t2 :
t1: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg3′; public $test2 = (refcount=1, is_ref=0)=’cap!’ }
t2: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg3′; public $test2 = (refcount=1, is_ref=0)=’cap!’ }
Ignoring echo1 & echo2 because of this: What is exactly happening when instantiating with ‘new’? & expected behaviour.
Considering echo3:
echo3: After assigning $t1->test = “msg2” :
t1: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg2′ }
t2: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg2′ }
This is understandable as I am just changing $t1->test variable and no direct change to &t2->test.
Considering echo4, where a direct change to $t2->test is done:
echo4: After assigning $t2->test=”msg3″ :
t1: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg3′ }
t2: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg3′ }
No C.O.W takes place! and the change is reflected to $t1 as well even though is_ref is not set.
Considering echo5, where the variable $test2 is injected into $t2:
echo5: After injecting $test2 to $t2 :
t1: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg4′; public $test2 = (refcount=1, is_ref=0)=’cap!’ }
t2: (refcount=2, is_ref=0)=class a { public $test = (refcount=1, is_ref=0)=’msg4′; public $test2 = (refcount=1, is_ref=0)=’cap!’ }
Again, no C.O.W takes place! and the change is reflected to $t1 as well even though is_ref is not set.
Why is this behaviour!?
It does but you’re having the wrong expectation.
The value is an object identifier. You assign that to
$t1or$t2. The object identifier is copied on write, but it still refers to the same object, so the object isn’t copied in any of the cases you outline in your question.See Objects and referencesDocs:
C.O.W. is an optimization. PHP here sees that
$t1->testand$t2->testare actually the same value. So if you change it, the optimization kicks in in the sense that there is nothing to copy at all.