コールバック / Callable

コールバックは、callable 型で表されます。

call_user_funcusort 等の関数は、ユーザーが定義するコールバック関数を引数として受け入れます。 コールバック関数は、単純な関数だけでなく、オブジェクトのメソッド あるいはクラスのstaticメソッドであってもかまいません。

受け渡し

PHP 関数はその名前を単に文字列として渡します。 どのようなビルトインまたはユーザー定義の関数も渡すことができます。 ただし、 array, echo, empty, eval, exit, isset, list, print あるいは unset といった言語構造はコールバックとしては使えないことに注意しましょう。

オブジェクトのインスタンスを渡すには配列を使います。 配列の 0 番目の要素にオブジェクトを、 そして 1 番目の要素にメソッド名を指定します。 protected メソッドや private メソッドは、クラスの内部からはアクセスできます。

static メソッドの場合、オブジェクトのインスタンスは不要です。 0 番目の要素として、オブジェクトのかわりにクラス名を指定します。 'ClassName::methodName' 形式で指定することもできます。

一般的なユーザー定義関数とは異なり、 無名関数アロー関数 もパラメータとして渡せます。

注意:

PHP 8.1.0 以降では、 無名関数を作るための記法として、第一級callableを生成する記法 も使えます。

一般的には、 __invoke() を実装した任意のオブジェクトもパラメータとして渡せます。

例1 コールバック関数の例

<?php 

// コールバック関数の例
function my_callback_function() {
    echo 'hello world!';
}

// コールバックメソッドの例
class MyClass {
    static function myCallbackMethod() {
        echo 'Hello World!';
    }
}

// タイプ 1: 単純なコールバック
call_user_func('my_callback_function'); 

// タイプ 2: staticメソッドのコール
call_user_func(array('MyClass', 'myCallbackMethod')); 

// タイプ 3: オブジェクトメソッドのコール
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));

// タイプ 4: staticメソッドのコール
call_user_func('MyClass::myCallbackMethod');

// タイプ 5: 相対指定によるstaticメソッドのコール
class A {
    public static function who() {
        echo "A\n";
    }
}

class B extends A {
    public static function who() {
        echo "B\n";
    }
}

call_user_func(array('B', 'parent::who')); // A, 但し PHP 8.2.0 以降は非推奨

// タイプ 6: __invoke を実装したオブジェクトを callable として用いる
class C {
    public function __invoke($name) {
        echo 'Hello ', $name, "\n";
    }
}

$c = new C();
call_user_func($c, 'PHP!');
?>

例2 クロージャを使ったコールバックの例

<?php
// クロージャ
$double = function($a) {
    return $a * 2;
};

// 数値の範囲
$numbers = range(1, 5);

// ここでクロージャをコールバックとして使用し、
// 指定した範囲の各要素の二倍の値を計算します
$new_numbers = array_map($double, $numbers);

print implode(' ', $new_numbers);
?>

上の例の出力は以下となります。

2 4 6 8 10

注意:

call_user_funccall_user_func_array で登録されたコールバックは、 前のコールバックからスローされた例外がキャッチされていない場合はコールされません。