June 08, 2008

php - cloning an object

あるクラスの多くのインスタンスを必要とする時、newでそれぞれのインスタンスを生成するよりも、一つのインスタンスを複製(クローン)した方がパフォーマンスが良い。
class Foo
{
  public $obj = null;
  public $var = "foo";
  
  public function __construct()
  {
    $obj = new stdClass();
    $obj->a = 10;
    $obj->b = 20;
    
    $this->obj = $obj;
  }
}
まずは一つ一つ、それぞれnewでインスタンスを生成する。
$objs = array();
$start = microtime();
for ($i = 0; $i < 10000; $i++) {
  $objs[] = new Foo();
}

var_dump(microtime() - $start);
var_dump(memory_get_peak_usage(true));
上記コードの所要時間と使用メモリ量。
float(0.0505634)  // 50.6 msec
int(6553600)  // 6554 KB
次は最初にインスタンスを生成し、それを複製する。
$objs = array();
$start = microtime();
$foo = new Foo();
for ($i = 0; $i < 10000; $i++) {
  $objs[] = clone $foo;
}

var_dump(microtime() - $start);
var_dump(memory_get_peak_usage(true));
結果、所要時間は先程の半分以下、メモリ使用量は約半分になる。
float(0.019881)   // 19.9 msec
int(3407872)  // 3408 KB
メモリ使用量が減るのは、それぞれのインスタンスが保持する$objが同じオブジェクトを参照しているため。以下のコードを実行することでそれを確認できる。
$foo  = new Foo();
$foo2 = clone $foo;

$foo2->var = "bar";
$foo2->obj->a = 100;
$foo2->obj->b = 200;

var_dump($foo->var);   // "foo"
var_dump($foo2->var);  // "bar"

var_dump($foo->obj->a);   // 100
var_dump($foo2->obj->a);  // 100

var_dump($foo->obj->b);   // 200
var_dump($foo2->obj->b);  // 200
この挙動だと困る場合は__clone()メソッド(クローンの時にコールされるマジックメソッド)を実装し、内部のオブジェクトも複製する。
class Foo
{
  ...
  
  public function __clone()
  {
    $this->obj = clone $this->obj;
  }
}
$foo  = new Foo();
$foo2 = clone $foo;

$foo2->var = "bar";
$foo2->obj->a = 100;
$foo2->obj->b = 200;

var_dump($foo->var);   // "foo"
var_dump($foo2->var);  // "bar"

var_dump($foo->obj->a);   // 10
var_dump($foo2->obj->a);  // 100

var_dump($foo->obj->b);   // 20
var_dump($foo2->obj->b);  // 200
ただ、これだと一つ一つインスタンスを生成するのとそう変わらない。
float(0.0442957)  // 44.3 msec
int(6029312)  // 6030 KB
使えるところでは使ったほうが吉。
ただ、「使えるところ」はあまりないかも。

トラックバックURL

コメントする

名前:
URL:
  情報を記憶: 評価:  顔   星
 
 
 
Sabel

Sabel PHP Frameworkを開発しています。
http://www.sabel.jp/

Search
Categories
Tags
Recent Articles
Archives