おぎろぐはてブロ

なんだかんだエンジニアになって10年以上

callback疑似型 / 可変長引数の親クラスのメソッドを呼び出す

前回の続き。
前回説明した、call_user_func call_user_func_arrayのように引数として、callback(疑似)型を受ける関数がいろいろあります。

mixed call_user_func( callback $function [, mixed $parameter [, mixed $...]] )
mixed call_user_func_array( callback $function, array $param_arr )
bool usort( array &$array, callback $cmp_function )
bool array_walk( array &$array, callback $funcname [, mixed $userdata] )

「擬似的な型」とマニュアルに書かれているのは、実際にはそんな型はなく、コールバック関数を指定する引数を詰めるとこですよと分かりやすくしているため。

callbackのパターン

このcallbackの指定には、PHPマニュアルに書いてあるように3つのパターンがあります。

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

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

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

// タイプ 2: スタティッククラスメソッドのコール
call_user_func(array('MyClass', 'myCallbackMethod'));

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

注: タイプ2はPHP5ではE_STRICTエラーとなります。static宣言していないのにstaticとしてコールしているためで、この場合は、メソッドを public static function myCallbackMethod()としてください。

ということで、

  1. 普通に文字列で関数名を指定する
  2. array(クラス名, メソッド名)の文字列配列で、staticなクラスメソッドを指定する
  3. array(object $obj, メソッド名)の配列で、オブジェクトのメソッドをコールする

できそうでできないのが、call_user_func('MyClass::myCallbackMethod')

無名コールバック関数は、無名ではない

callbackのところの一文。

一般的なユーザ定義関数とは異なり、create_function() では無名コールバック関数を作成することができます。

komagataさんのとこで記事が上がっていたけど、無名ではない。普通には呼び出せない名前の付けられた関数。
コメント欄に書かれているように関数名として許容されないNULL文字が入ってるだけ。うーむ。

継承元クラスを呼び出す

くまさんに聞かれて、自分も知らなかったのでメモ。

<?php
class Base
{
    public function hogeMethod()
    {   
        $args = func_get_args();
        echo "Base::hogeMethod() called, args: ", join(", ", $args), "\n";
    }
}

class Extend extends Base 
{
    public function hogeMethod()
    {   
        $args = func_get_args();
        echo "Extend::hogeMethod() called, args: ", join(", ", $args), "\n";
    }
}

$obj = new Extend;
$obj->hogeMethod("a", "b", "c");
?>

このように継承時にメソッドをオーバーライドして、親の同じメソッドを呼び出したいことがよくある。引数の個数が可変でなければ(デフォルトパラメータの場合も)、

public function hogeMethod($a, $b, $c = NULL)
{   
    parent::hogeMethod($a, $b, $c);
}

と呼べばよい。
けれども、引数の数が可変の場合は、こう呼び出せない。この場合は、call_user_func()を使うことになり、以下のようになる。

class Extend extends Base 
{
    public function hogeMethod()
    {   
        $args = func_get_args();
        echo "Extend::hogeMethod() called, args: ", join(", ", $args), "\n";

        // 可変個の引数でこうやって呼び出す
        call_user_func_array(array($this, "parent::hogeMethod"), $args);
    }
}

callbackを、array($this, "parent::hogeMethod") もしくは array($this, "Base::hogeMethod")とすれば呼び出せる。call_user_func('MyClass::myCallbackMethod')が使えないのに、なんだか気持ち悪いけど。
クラス内からでなく、外から Base::hogeMethod()を叩くときは、

$obj = new Extend;
call_user_func(array($obj, "Base::hogeMethod"), "a", "b", "c");

と、クラス内と同じようにコールできます。
意味は無いですが、static methodであれば、

call_user_func(array('Base', 'Base::hogeMethod'), "a", "b", "c");

とも呼び出せます。

こういう妙な動きをしてると、コードが気になるので、ソースコードを読んでみることにします。