2012-01-01 49 views
1
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/>"; 

輸出:爲什麼C.O.W在'寫入物業'/'將物業注入物品中'時不會發生?

ECHO1:實例化後:
T1:(引用計數= 1,is_ref = 0)= A類{公共$測試=(引用計數= 2,is_ref = 0)= 'MSG1'}

echo2的:分配$ t1到$ t2以後:
T2:(引用計數= 2,is_ref = 0)= A類{公共$測試=(引用計數= 2,is_ref = 0)= 'msg1'}

echo3:分配$ t後1-> test =「msg2」:
t1:(refcount = 2,is_ref = 0)= class a {public $ test =(refcount = 1,is_ref = 0)='msg2'}
t2:(refcount = 2,is_ref = 0)= A類{公共$測試=(引用計數= 1,is_ref = 0)= 'MSG2'}

echo4:分配$ T2->測試= 「消息3」 之後:
t1:(refcount = 2,is_ref = 0)= class a {public $ test =(refcount = 1,is_ref = 0)='msg3'}
t2:(refcount = 2,is_ref = 0)= class a {公共$ test =(refcount = 1,is_ref = 0)='msg3'}

echo5:向$ t2注入$ test2之後:
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 & echo2因爲這樣:What is exactly happening when instantiating with 'new'? &預期行爲。

考慮echo3

echo3:分配$ T1-後>測試= 「MSG2」:
T1:(引用計數= 2,is_ref = 0)= A類{公共$測試=(引用計數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-後>測試= 「消息3」:
T1:(引用計數= 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'}

沒有COW發生!並且該變更也反映爲$t1,即使未設置is_ref也是如此。

考慮echo5,其中變量$test2被注入$t2

echo5:
T1:(引用計數= 2,is_ref = 0)= A類{公共注入$ TEST2到$ t2以後$ 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發生!並且該變更也反映爲$t1,即使未設置is_ref也是如此。

Why is this behaviour!?

回答

2

它做,但你有錯誤的期望。

該值是一個對象標識符。您將其分配給$t1$t2。對象標識符在寫入時被複制,但它仍然引用同一個對象,因此該對象不會被複制到您在問題中概述的任何情況中。

Objects and references­Docs

一個經常被提到的PHP 5 OOP的關鍵點之一是「對象是通過引用傳遞默認」。這並不完全正確。 [...]從PHP 5開始,對象變量不再包含對象本身作爲值。它只包含一個對象標識符,它允許對象訪問器找到實際的對象。

C.O.W.是一種優化。 PHP在這裏看到$t1->test$t2->test實際上是相同的值。所以,如果你改變了它,那麼這個優化就會開始,因爲根本沒有什麼可以複製的。

+0

正在看........ – ThinkingMonkey 2012-01-01 10:55:42

+0

好吧。將做..... – ThinkingMonkey 2012-01-01 11:10:17

+0

完成分配後,因爲兩者都指向同一個zval容器,所以變更得到反映。具有「引用賦值」的要點是,如果,$ t1 = new a; $ t2 =&$ t1,$ t2 = new b;現在,$ t1和$ t2都將指向b類對象的zval容器? – ThinkingMonkey 2012-01-01 11:13:17