call_user_funcの履歴

$func = 'callback';
$arg1 = 'Hello';
$arg2 = 'World';
$result = call_user_func($func, $arg1, $arg2);
echo $result;
function callback($arg1, $arg2){
  return $arg1 . ' ' . $arg2;
}

> Hello World

テスト1

コード

require_once('Benchmark/Timer.php');
$func = 'concat';
$arg1 = 'Hello';
$arg2 = 'World';
$st = new str();

$b = new Benchmark_Timer();
$b->start();
for ($i = 0; $i < 100000; $i++){
    concat($arg1, $arg2);
}
$b->setMarker('org');
for ($i = 0; $i < 100000; $i++){
    $st->$func($arg1, $arg2);
}
$b->setMarker('string');
for ($i = 0; $i < 100000; $i++){
    call_user_func($func, $arg1, $arg2);
}
$b->setMarker('call_user_func');
$b->display();
function concat($arg1, $arg2){
  return $arg1 . ' ' . $arg2;
}
class str{
    function concat($arg1, $arg2){
      return $arg1 . ' ' . $arg2;
    }
}

結果

-------------------------------------------------------------
marker           time index            ex time         perct   
-------------------------------------------------------------
Start            1213551357.49549100   -                0.00%
-------------------------------------------------------------
org              1213551358.56999200   1.074501        25.35%
-------------------------------------------------------------
call_user_func   1213551360.59016900   2.020177        47.66%
-------------------------------------------------------------
string           1213551361.73394500   1.143776        26.98%
-------------------------------------------------------------
Stop             1213551361.73417100   0.000226         0.01%
-------------------------------------------------------------
total            -                     4.238680       100.00%
-------------------------------------------------------------

テスト2:call_user_func

コード

require_once('Benchmark/Timer.php');
$func = 'concat';
$arg1 = 'Hello';
$arg2 = 'World';
$st = new str();

$b = new Benchmark_Timer();
$b->start();
for ($i = 0; $i < 100000; $i++){
    call_user_func($func, $arg1, $arg2);
}
$b->setMarker('call_user_func');
for ($i = 0; $i < 100000; $i++){
    call_user_func(array($st, 'concat'), $arg1, $arg2);
}
$b->setMarker('call_user_func(obj)');
for ($i = 0; $i < 100000; $i++){
    call_user_func(array($st, 'concat'), $arg1, $arg2);
}
$b->setMarker('call_user_func_array(obj)');
for ($i = 0; $i < 100000; $i++){
    call_user_func(array('str', 'concat'), $arg1, $arg2);
}
$b->setMarker('call_user_func(static)');
$b->display();
function concat($arg1, $arg2){
  return $arg1 . ' ' . $arg2;
}
class str{
    function concat($arg1, $arg2){
      return $arg1 . ' ' . $arg2;
    }
}

結果

------------------------------------------------------------------------
marker                      time index            ex time         perct   
------------------------------------------------------------------------
Start                       1213551872.93670100   -                0.00%
------------------------------------------------------------------------
call_user_func              1213551874.89791800   1.961217        21.03%
------------------------------------------------------------------------
call_user_func(obj)         1213551877.40661200   2.508694        26.90%
------------------------------------------------------------------------
call_user_func_array(obj)   1213551879.75447900   2.347867        25.17%
------------------------------------------------------------------------
call_user_func(static)      1213551882.26413500   2.509656        26.91%
------------------------------------------------------------------------
Stop                        1213551882.26432900   0.000194         0.00%
------------------------------------------------------------------------
total                       -                     9.327628       100.00%
------------------------------------------------------------------------

考察

  • 動的メソッド呼び出しは、call_user_funcを使うよりも$func()を使う方が速い。コードにそのままメソッド書くのと大して変わらない。
  • クラスメソッドをstaticに呼び出す場合、staticキーワードをつけないと、1.5倍ぐらい遅くなる。


引数を可変にしたい場合はcall_user_func_arrayを使うしかないけど、そうでない場合は$func()を使う方がいい。call_user_funcと$func()の違いは、メソッドが存在しない場合、前者はWarningなのに対して、後者はFatalになる。