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

出力:

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)='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!' }

無視してこれが原因: 「new」でインスタンス化するecho1、正確に何が起こっているのでしょうか。&期待される動作。echo2

検討中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->test変数を変更するだけで、に直接変更することはないので、これは理解でき&t2->testます。

を考慮echo4して、への直接変更$t2->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'}

COWは発生しません!$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!' }

繰り返しますが、COWは発生しません!$t1設定されていなくても、変更はに反映されis_refます。

Why is this behaviour!?

4

1 に答える 1

2

それはありますが、あなたは間違った期待を持っています。

値はオブジェクト識別子です。$t1またはに割り当て$t2ます。オブジェクト識別子は書き込み時にコピーされますが、それでも同じオブジェクトを参照しているため、質問で概説したどの場合でもオブジェクトはコピーされません。

オブジェクトとリファレンスを参照してくださいドキュメント:

よく言及されるPHP5OOPの重要なポイントの1つは、「オブジェクトはデフォルトで参照によって渡される」ということです。これは完全には真実ではありません。[...] PHP 5以降、オブジェクト変数にはオブジェクト自体が値として含まれなくなりました。これには、オブジェクトアクセサが実際のオブジェクトを見つけることができるオブジェクト識別子のみが含まれています。

COWは最適化です。ここでのPHPはそれを認識して$t1->testおり$t2->test、実際には同じ値です。したがって、変更すると、コピーするものがまったくないという意味で最適化が始まります。

于 2012-01-01T10:51:20.673 に答える