【问题标题】:Why C.O.W does not take place when ' writing to a property ' / ' injecting a property into an object ' of class?为什么在“写入属性”/“将属性注入类的对象”时不会发生 C.O.W?
【发布时间】:2012-01-31 08:04:41
【问题描述】:
 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->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->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)='cap!' }
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!' }

忽略 echo1echo2,因为:What is exactly happening when instantiating with 'new'? 和预期行为。

考虑echo3

echo3:分配 $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' }

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

考虑到echo4,直接更改为$t2-&gt;test

echo4:分配 $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' }

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

考虑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)='cap!' }
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 发生!即使未设置is_ref,更改也会反映到$t1

Why is this behaviour!?

【问题讨论】:

    标签: php reference php-internals


    【解决方案1】:

    确实如此,但您的期望是错误的。

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

    Objects and references­Docs:

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

    C.O.W.是一种优化。 PHP 这里看到$t1-&gt;test$t2-&gt;test 实际上是同一个值。因此,如果你改变它,优化就会启动,因为根本没有什么可复制的。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-03
    • 1970-01-01
    • 2022-09-28
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    相关资源
    最近更新 更多