php オブジェクト内のメソッドをcallback関数として渡す場合の注意点

array_filterやarray_mapなどcallback関数を引数にとる関数がphpには多く存在します。

callback関数の渡し方でのハマりどころが1点あったので共有しておきます。

ほとんどのケースが例1 コールバック関数の例に記載されていますが、 オブジェクト内から同じオブジェクト内のメソッドをコールする場合の記載がありません。(タイプ 3: オブジェクトメソッドのコールと同等なので必要ないと言えばないのですが)

オブジェクト内から同じオブジェクト内のメソッドをコールする

1.誤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CallBack {

    private $arr;

    public function __construct($arr) {
        $this->arr = $arr;
    }

    public function my_callback($val) {
        return ($val % 2 === 0);
    }

    public function run() {
        print_r(array_filter($this->arr, 'my_callback'));
    }

}

$callback = new CallBack(array(1, 2, 3, 4, 5, 6));
$callback->run();

上記のコードは一見正しく見えますが実行すると Warning: array_filter() expects parameter 2 to be a valid callback, function 'my_callback' not found or invalid function name とエラーになります。

同じオブジェクト内からコールする場合でもcallbackは配列で指定する必要があります。

2.正
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class CallBack {

    private $arr;

    public function __construct($arr) {
        $this->arr = $arr;
    }

    public function my_callback($val) {
        return ($val % 2 === 0);
    }

    public function run() {
        // オブジェクト自身を指定
        print_r(array_filter($this->arr, array($this, 'my_callback')));
    }

}

$callback = new CallBack(array(1, 2, 3, 4, 5, 6));
$callback->run();

注意. オブジェクトは常に指定すること

1.誤のコードでもエラーなく動作させることはできます。

以下のコードを実行するとエラーは発生せず、結果としてArray ( [0] => 1 [2] => 3 [4] => 5)が出力されます。

名前の一致が生じて予期しない挙動をしておりバグの元となるので、オブジェクトは常に指定するよう注意しましょう。

2.正
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function my_callback($val) {
    return ($val % 2 !== 0);
}

class CallBack {

    private $arr;

    public function __construct($arr) {
        $this->arr = $arr;
    }

    public function my_callback($val) {
        return ($val % 2 === 0);
    }

    public function run() {
        // array(2, 4, 6)が出力されることを期待
        print_r(array_filter($this->arr, 'my_callback'));
    }

}

$callback = new CallBack(array(1, 2, 3, 4, 5, 6));
$callback->run();

参考

PHP コールバック

Comments