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使えるところでは使ったほうが吉。
ただ、「使えるところ」はあまりないかも。