【訂正】
速度の比較で、関数だけは実行時間が入っていたので、比較対象から外しました。それにともなって、タイトルを変更しました。
【/訂正】
PHPのクロージャーのおかげで、コードをデータのように使えるようになりました。ちょっとした設定とか、コードで記述できて便利です。
ところで、パフォーマンスはどうなのでしょう?
PHPの内部では、クロージャーは__invoke
のあるオブジェクトとして実装されている、と聞いているので、おそらくクラスをnewするのと似たような速度かなと思います。今さらながら、遅かったらどうしよう、という疑問が…
ということで計測してみました。
比較対象は、クロージャー、クラスをnew、ついでにクローンと関数も比較してみました。
結果
closure: 491.33 msec
new class: 437.70 msec
clone obj: 353.54 msec
実行環境:mac mini, Core i7, 16GB, PHP5.6.16
感想
予想通り、クロージャーもnewも似たような数字になりました。少しnewの方が速いのですね。クロージャーのほうが、少し複雑なオブジェクトなのかもしれません。
意外だったのが、関数呼び出しが一番遅かったこと。
関数にするより、クロージャー使ったりオブジェクトを作るほうが速いとは。と言っても、3〜4倍程度なので、そもそもが速いので、気にすることはないですが。
クローンは速いと聞いてたのですが、やはり一番早かったです。でも、似たような数字ですね。
PHP7
PHP7でも試してみたいですね。
同じく導入される無名クラスも、一応測ってみたい。
結論
コードによる速度差なんか気にしなくてOK!
コード
測定に使ったコードです。
<?php
function runIt($closure, $title)
{
$n = 1000000;
$time1 = microtime(true);
$closure($n);
$time2 = microtime(true);
echo sprintf("%12s: %8.2f msec\n", $title, ($time2 - $time1) * 1000);
};
$do_closure = function ($n = 100)
{
for($i = 0; $i < $n; $i++) {
$s = function() use($i) {return 'hi';};
}
};
class sample {
function __invoke() {
return 'hi';
}
}
$do_class = function ($n = 100)
{
for($i = 0; $i < $n; $i++) {
$s = new sample($i);
}
};
$do_clone = function ($n = 100)
{
$s0 = new sample();
for($i = 0; $i < $n; $i++) {
$s = clone $s0;
}
};
function test_func($i) {
return 'hi';
}
$do_function = function ($n = 100)
{
for($i = 0; $i < $n; $i++) {
$s = test_func($i);
}
};
//runIt($do_function, 'function');
runIt($do_closure, 'closure');
runIt($do_class, 'new class');
runIt($do_clone, 'clone obj');