2012-04-09 5 views
3

新しいオブジェクトの参照が元のオブジェクトのものではなく、独自のメソッドやプロパティを指すように、複数の参照を含む複雑なPHPオブジェクトのクローンを作成する最良の方法は何ですか?PHP - 自身への参照を含むオブジェクトをクローンしますか?

from the manual私は、$new_object = clone $old_object;が参照を保持する浅いコピーを作成することを理解しています。おそらく$ new_objectの参照は古いオブジェクトのメソッドを指していますか?

このマニュアルページのコメントからは、$new_object = unserialize(serialize($old_object));がディープコピーを作成する方法であることが示されています。このアプローチが私の場合に何を意味するのかは確かではありません。つまり、参照がクローンを指すように変換されているのか、絶対に作られているのか、それとも何か他のものに変換されているのかどうかはわかりません。

これを行う標準的な方法が確立しているかどうかを知りたいと思います。

(注:問題のオブジェクトはDrupal Viewsオブジェクトですが、この問題は一般的にPHPオブジェクトに関するものです。このオブジェクトの唯一の重要な機能は、巨大であり、 。あなたはツリー全体をナビゲートしようとした場合)

答えて

3

を簡単なテストでは何が起こるかを明らかにする:

$old = new stdClass(); 
$old->foo = 'bar'; 
$old->baz = &$old; 

print_r($old); 

$new = unserialize(serialize($old)); 

$new->foo = 'new'; 

print_r($new); 
print_r($new->baz->foo); 

このコードは、自己refが今クローンを指していることを示しています。 http://codepad.org/dSnZ5I10

+0

クール、ありがとうございます。これが良い一般化可能で標準的なアプローチであるかどうかについてのあらゆる考え方。オブジェクトが巨大なときにパフォーマンスの欠点がある場合は?私のテストでは大丈夫だと思われますが、テストは非常に基本的です。 – user568458

+1

オブジェクトのサイズが大きくなるほど処理速度が遅くなりますが、そのようになります。あなたのオブジェクトの大きさに依存していると思います。シリアル化されたバージョンは、メモリの半分以上を占めています(strlen()はどれくらい大きいかを教えてくれます)。悪いですが、それ以外の場合、実行時間は些細なものでなければなりません。 – Cal

+0

ですから、メモリは単純に== strlen(serialize($ object))を使用してください - それは意味があり、私の質問に答えます。ありがとう! – user568458

2

ここにいくつかの基本的なテストと結果があります。完全な答えではありませんが、うまくいくと便利です。私のアプローチが間違っている場合は、私も修正してください。 $ビューがすでに自己参照やデータの負荷の多くを含むオブジェクトであると仮定します

 $view->somedata = "This is the default"; 
     $view->selfreference =& $view->somedata; 

     $new = clone $view; 
     $new2 = unserialize(serialize($view)); 

     $view->somedata = "This is view"; 
     $new->somedata = "This is new"; 
     $new2->somedata = "This is new2"; 

     echo("$view: ".$view->selfreference); 
     echo("$new: ".$new->selfreference); 
     echo("$new2: ".$new2->selfreference); 

結果:

'$view: This is new' 
'$new: This is new' 
'$new2: This is new2' 

だから最初の調査では、それはcloneポイント浅いクローンのように見えますオリジナルへの自己参照、およびunserialize(serialize())アプローチは参照を維持し、それを新しいオブジェクトにポイントします。

したがって、unserialize(serialize())のように見え、無限ループまたは過度の再帰でクラッシュすることはありません。私はこれが最高、標準、および/または容認されたアプローチであるかどうかについて人々の考えを聞きたい。

関連する問題