为什么C.O.W在“写入属性”/“将属性注入类的对象”时不会发生?

时间:2012-01-01 10:24:13

标签: php reference php-internals

 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/>";

输出:

  

echo1:实例化后:
  t1:(refcount = 1,is_ref = 0)= class a {public $ test =(refcount = 2,is_ref = 0)='msg1'}

     

echo2:将$ t1分配给$ t2后:
  t2:(refcount = 2,is_ref = 0)= class a {public $ test =(refcount = 2,is_ref = 0)='msg1'}

     

echo3:分配$ t1-&gt; 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:分配$ t2-&gt; 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:将$ test2注入$ t2后:
  t1:(refcount = 2,is_ref = 0)= class a {public $ test =(refcount = 1,is_ref = 0)='msg3'; public $ test2 =(refcount = 1,is_ref = 0)='c ap!' }
  t2:(refcount = 2,is_ref = 0)= class a {public $ test =(refcount = 1,is_ref = 0)='msg3'; public $ test2 =(refcount = 1,is_ref = 0)='c
ap!' }

忽略echo1&amp; echo2因此:What is exactly happening when instantiating with 'new'?&amp;预期的行为。

考虑echo3

  

echo3:分配$ t1-&gt; 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'}

这是可以理解的,因为我只是更改了$t1->test变量而没有直接更改为&t2->test

考虑echo4,直接更改为$t2->test

  

echo4:分配$ t2-&gt; 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'}

没有C.O.W发生! <!1}}即使未设置$t1,也会将更改反映到is_ref

考虑echo5,将变量$test2注入$t2

  

echo5:将$ test2注入$ t2后:
  t1:(refcount = 2,is_ref = 0)= class a {public $ test =(refcount = 1,is_ref = 0)='msg4'; public $ test2 =(refcount = 1,is_ref = 0)='c ap!' }
  t2:(refcount = 2,is_ref = 0)= class a {public $ test =(refcount = 1,is_ref = 0)='msg4'; public $ test2 =(refcount = 1,is_ref = 0)='c
ap!' }

再次,没有C.O.W发生! <!1}}即使未设置$t1,也会将更改反映到is_ref

Why is this behaviour!?

1 个答案:

答案 0 :(得分:2)

确实如此,但你有错误的期望。

该值是对象标识符。您可以将其分配给$t1$t2。对象标识符在写入时复制,但它仍然引用同一个对象,因此在您在问题中概述的任何情况下都不会复制该对象。

请参阅Objects and references­Docs

  

经常提到的PHP 5 OOP的一个关键点是&#34;对象默认通过引用传递&#34;。这不完全正确。 [...]从PHP 5开始,对象变量不再包含对象本身作为值。它只包含一个对象标识符,允许对象访问者查找实际对象。

C.O.W。是一种优化。 PHP在这里看到$t1->test$t2->test实际上是相同的值。因此,如果你改变它,那么优化就会在没有任何东西可以复制的情况下发挥作用。