LoginSignup
2
2

More than 3 years have passed since last update.

PHPコールバック関数入門

Last updated at Posted at 2020-06-23

Callable

PHPの要素で関数として呼び出すことができるものをコールバックまたは callable といいます。

参考:PHP: コールバック / Callable - Manual

本記事のタイトルにもあるとおり、コールバック関数といわれることもあるようです(実際 PHP マニュアルにも書かれています)。

無用な混乱をさけるため、本記事では呼び方を callable で統一することにします。

Examples

説明を読んだだけでは理解できないと思いますので、callable の例をたくさんみていくことにしましょう。

例1

PHP
function hello() {
    echo 'こんにちは。';
}

echo is_callable('hello') . PHP_EOL;

call_user_func('hello');
result
1
こんにちは。

5行目のis_callableは、引数が callable であるかどうかを調べてくれる関数です。

is_callable — 引数が、関数としてコール可能な構造であるかどうかを調べる

PHP: is_callable - Manual

引数が callable ならtrueを、 そうでなければfalseを返します。
また、echo true1を出力しecho falseは何も出力しません。

上記の例では1が出力されていますので、is_callbleの引数である文字列hellocallable であることがわかりました。
callable であるということは、文字列helloを関数として呼び出せるということです。

実際に、7行目でcall_user_funcという関数をつかって callable である文字列helloを関数として呼び出しています。

call_user_func — 最初の引数で指定したコールバック関数をコールする

PHP: call_user_func - Manual

こんにちは。と出力されていますので、1〜3行目で定義されている関数helloが呼び出されたことがわかりますね。

一般に、関数fooが定義されているとき文字列foocallable となります。
このとき文字列foocall_user_funcにわたすことによって、関数fooを呼び出すことができます。

例2

PHP
function hello() {
    echo 'こんにちは。';
}

echo is_callable(hello) . PHP_EOL;

call_user_func(hello);
PHP Warning:  Use of undefined constant hello - assumed 'hello' (this will throw an Error in a future version of PHP) in ...
PHP Warning:  Use of undefined constant hello - assumed 'hello' (this will throw an Error in a future version of PHP) in ...

今回はエラーが出てしまいました。

エラーメッセージをよく読むとUse of undefined constant hello - assumed 'hello'と書かれています。
これは「定義されていない定数helloをつかっているようだけど、それは文字列helloのことじゃないか?」という意味です。

例1の5行目と7行目では、helloを二つのシングルクォーテーション('')でかこむことによって、それが文字列であることを表していました。

今回の例では、シングルクォーテーションでかこむことをしなかったため、helloは定数として解釈されます。
このとき PHP は定数helloの値を関数にわたそうとします。
ところが定数helloは定義されていませんので、PHP はたいへん狼狽し、エラーメッセージを吐き、森へ帰ってしまったというわけです(?)。

PHP 関数はその名前を単に文字列として渡します。

PHP: コールバック / Callable - Manual

例3

PHP
function sum($int1, $int2) {
    return $int1 + $int2;
}

echo is_callable('sum') . PHP_EOL;

echo call_user_func_array('sum', [2, 5]);
result
1
7

1〜3行目で定義されている関数sumは、二つの数値をうけとって、それらの和を返すというものです。
これを実行するためにはsum(2, 5)のように二つの引数を指定する必要があります。

このような場合でも、文字列sum自体は callable です。
これは5行目の命令によって1が出力されていることからわかります。

さて、文字列sumcallable だということは、文字列sumを関数として呼び出せるということです。
sumのような引数を必要とする関数を callable によって呼び出したいときは、call_user_func_arrayという関数をつかいます。

call_user_func_array — パラメータの配列を指定してコールバック関数をコールする

PHP: call_user_func_array - Manual

第一引数には callable を、第二引数には呼び出される関数にわたしたい式を配列にしたものを指定します。

7行目では、call_user_func_arrayの第一引数には callable である文字列sumを、第二引数には配列[2, 5]を指定しました。
これによって関数sumが呼び出され、関数sumの第一引数には2が、第二引数には5がわたされます。
このとき関数sum25の和である7を返しますので、この7echoされて7が出力されたというわけです。

余談・・

つぎのコードは今回の例の7行目をecho call_user_func('sum');にとりかえたものです。
PHP
function sum($int1, $int2) {
    return $int1 + $int2;
}

echo is_callable('sum') . PHP_EOL;

echo call_user_func('sum');

これを実行すると、もちろんエラーが出るのですが、このときのエラーメッセージはつぎのようになります。

result
PHP Fatal error:  Uncaught ArgumentCountError: Too few arguments to function sum(), 0 passed in ... and exactly 2 expected in ......

「関数sumにわたす引数が少なすぎるよ!」といわれています。
ということは、関数sumの呼び出し自体は問題なく行われたということです。

先ほどみたとおり、文字列sum自体は callable でした。
ですので、call_user_funcの引数に文字列sumを指定してあげれば、関数sumを呼び出すこと自体は問題なくできるというわけです。


例4

PHP
$hello = function () {
  echo 'こんにちは。';  
};

echo is_callable($hello) . PHP_EOL;

call_user_func($hello);
result
1
こんにちは。

1〜3行目で、変数helloに無名関数を代入しています。

無名関数は callable です。
これは5行目の命令によって1が出力されていることからわかります。

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

PHP: コールバック / Callable - Manual

7行目では、call_user_funcに変数helloの値である無名関数をわたすことによって、その無名関数自身を呼び出しています。

ちなみに・・
PHP
$hello = function () {
  echo 'こんにちは。';  
};

var_dump($hello);
result
object(Closure)#1 (0) {
}

無名関数はPHPが用意しているClosureという特別なクラスのインスタンスとして実現されています。

無名関数の実装には Closure クラスを使っています。

PHP: 無名関数 - Manual


例5

PHP
class Player {
    private $name;

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

    public function getname() {
        return $this->name;
    }
}

$ichiro = new Player('イチロー');

echo is_callable([$ichiro, 'getname']) . PHP_EOL;

echo call_user_func([$ichiro, 'getname']);
result
1
イチロー

1〜10行目で、Playerクラスを定義しています。このクラスのなかでgetnameというメソッドを定義しました。
つづく12行目でPlayerクラスのインスタンスを作成し、変数ichiroに代入しています。

このとき、配列[$ichiro, 'getname']callable です。
この配列をcall_user_funcの引数に指定することで、変数ichiroに代入されたPlayerクラスのインスタンスのgetnameメソッドを呼び出すことができます。

オブジェクトのインスタンスを渡すには配列を使います。 配列の 0 番目の要素にオブジェクトを、 そして 1 番目の要素にメソッド名を指定します。

PHP: コールバック / Callable - Manual

イチローと出力されていることから、所期のメソッドが呼び出されたことがわかりますね。

例6

PHP
class Car {
    public static function honk() {
        echo 'ビッビー';
    }
}

echo is_callable(['Car', 'honk']) . PHP_EOL;

call_user_func(['Car', 'honk']);
result
1
ビッビー

1〜5行目で、Carクラスを定義し、そのなかでhonkという静的メソッドを定義しました。

このとき、配列['Car', 'honk']callable です。
この配列をcall_user_funcの引数に指定することで、Carクラスの静的メソッドhonkを呼び出すことができます。

静的なクラスメソッドの場合、オブジェクトのインスタンスは不要です。 0 番目の要素として、オブジェクトのかわりにクラス名を指定します。

PHP: コールバック / Callable - Manual

例7

PHP
class Car {
    public static function honk() {
        echo 'ビッビー';
    }
}

echo is_callable('Car::honk') . PHP_EOL;

call_user_func('Car::honk');
result
1
ビッビー

クラスの定義は例6とおなじです。

例6では、配列['Car', 'honk']callable であることをたしかめました。
今回の例は、文字列Car::honkもまた callable であることを表しています。

'ClassName::methodName' 形式で指定することもできます。

PHP: コールバック / Callable - Manual

クラスの静的メソッドを callable として表現する方法は二種類あるということですね。

おしまい

callable の例をたくさんみてきました。
これで callable とは何なのか、多少なりとも理解が深まったと思います。

また、本記事では説明が不十分な箇所も多々あるかと思います。
疑問に思うところがあったら、適宜 PHP マニュアル等を参照してください。

最後まで読んでいただき、ありがとうございました。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2