Php 为什么在';写入属性';/';将属性注入对象';什么课? a类{ public$test=“msg1”; } $t1=新a; echo“echo1:实例化后:”; xdebug_debug_zval('t1');回声“”; $t2=$t1; echo“echo2:将$t1分配给$t2后:”; xdebug_debug_zval('t2');回声“”; $t1->test=“msg2”; echo“echo3:在分配$t1->test=“msg2”之后:; xdebug_debug_zval('t1');回声“”; xdebug_debug_zval('t2');回声“”; $t2->test=“msg3”; echo'echo4:在分配$t2->test=“msg3”之后:; xdebug_debug_zval('t1');回声“”; xdebug_debug_zval('t2');回声“”; $t2->test2=“c*ap!”; echo“echo5:在将$test2注入$t2之后:”; xdebug_debug_zval('t1');回声“”; xdebug_debug_zval('t2');回声“”;
输出: echo1:实例化后:Php 为什么在';写入属性';/';将属性注入对象';什么课? a类{ public$test=“msg1”; } $t1=新a; echo“echo1:实例化后:”; xdebug_debug_zval('t1');回声“”; $t2=$t1; echo“echo2:将$t1分配给$t2后:”; xdebug_debug_zval('t2');回声“”; $t1->test=“msg2”; echo“echo3:在分配$t1->test=“msg2”之后:; xdebug_debug_zval('t1');回声“”; xdebug_debug_zval('t2');回声“”; $t2->test=“msg3”; echo'echo4:在分配$t2->test=“msg3”之后:; xdebug_debug_zval('t1');回声“”; xdebug_debug_zval('t2');回声“”; $t2->test2=“c*ap!”; echo“echo5:在将$test2注入$t2之后:”; xdebug_debug_zval('t1');回声“”; xdebug_debug_zval('t2');回声“”;,php,reference,php-internals,Php,Reference,Php Internals,输出: echo1:实例化后: t1:(refcount=1,is_ref=0)=a类{public$test=(refcount=2,is_ref=0)='msg1'} echo2:将$t1分配给$t2后: t2:(refcount=2,is_ref=0)=a类{public$test=(refcount=2,is_ref=0)='msg1'} echo3:在分配$t1->test=“msg2”后: t1:(refcount=2,is_ref=0)=a类{public$test=(refcou
t1:(refcount=1,is_ref=0)=a类{public$test=(refcount=2,is_ref=0)='msg1'}
echo2:将$t1分配给$t2后:
t2:(refcount=2,is_ref=0)=a类{public$test=(refcount=2,is_ref=0)='msg1'}
echo3:在分配$t1->test=“msg2”后:
t1:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg2'}
t2:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg2'}
echo4:分配$t2->test=“msg3”后:
t1:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg3'}
t2:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg3'}
echo5:将$test2注入$t2后:
t1:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg3';public$test2=(refcount=1,is_ref=0)='cap!'
t2:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg3';public$test2=(refcount=1,is_ref=0)='cap!' 忽略
echo1
和echo2
,原因是:&预期行为
考虑到echo3:
echo3:在分配$t1->test=“msg2”后:t1:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg2'}
t2:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg2'}
这是可以理解的,因为我只是更改了
$t1->test
变量,而没有直接更改&t2->test
考虑到echo4
,直接更改为$t2->test
:
echo4:分配$t2->test=“msg3”后:t1:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg3'}
t2:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg3'}
没有发生抢劫!即使未设置
is_ref
,更改也会反映到$t1
考虑到echo5
,其中变量$test2
被注入$t2
:
echo5:将$test2注入$t2后:t1:(refcount=2,is_ref=0)=a类{public$test=(refcount=1,is_ref=0)='msg4';public$test2=(refcount=1,is_ref=0)='cap!'
t2:(refcount=2,is_-ref=0)=a类{public$test=(refcount=1,is_-ref=0)='msg4';public$test2=(refcount=1,is_-ref=0)='cap!' 再说一次,没有发生抢劫!即使未设置
is_ref
,更改也会反映到$t1
为什么会有这种行为代码>确实如此,但您的预期是错误的
该值是一个对象标识符。您将其分配给$t1
或$t2
。对象标识符在写入时被复制,但它仍然引用同一个对象,因此在您在问题中概述的任何情况下都不会复制该对象
见:
PHP5OOP中经常提到的一个关键点是“默认情况下对象是通过引用传递的”。这并不完全正确。[…]从PHP5开始,对象变量不再包含对象本身作为值。它只包含一个允许对象访问器查找实际对象的对象标识符
C.O.W.是一种优化。PHP在这里看到$t1->test
和$t2->test
实际上是相同的值。因此,如果您对其进行更改,则优化将从根本不需要复制的意义上开始。当分配完成时,由于两者都指向同一个zval容器,因此更改将得到反映。拥有参考赋值的要点是,如果$t1=新的a$t2=和$t1,$t2=新b;现在,$t1和$t2都将指向b类对象的zval容器?$t2=&$t1
将使$t2
成为$t1
的别名。因此,您可以使用两个变量名来访问相同的值。两者都指同一个zval容器。另请参见,其中显示了创建引用(任何类型,而不仅仅是对象)时发生的情况。但是请注意,对象“值”表示为bespoken对象标识符。Hmmmmm。我已经阅读了refcounting基础知识,即使有您的解释,在我的脑海中仍然不清楚:(但是,感谢您的帮助。如果您真的想完全深入了解该理论:PHP如何在内部管理这些结构,这可能很有趣:
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/>";