PHPにコールバックを実装するにはどうすればよいですか?


回答:


173

このマニュアルでは、「コールバック」と「呼び出し可能」という用語を同じ意味で使用していますが、「コールバック」は従来、関数ポインタのように機能する文字列または配列値を指し、将来の呼び出しのために関数またはクラスメソッドを参照します。これにより、PHP 4以降、関数型プログラミングのいくつかの要素が可能になりました。フレーバーは次のとおりです。

$cb1 = 'someGlobalFunction';
$cb2 = ['ClassName', 'someStaticMethod'];
$cb3 = [$object, 'somePublicMethod'];

// this syntax is callable since PHP 5.2.3 but a string containing it
// cannot be called directly
$cb2 = 'ClassName::someStaticMethod';
$cb2(); // fatal error

// legacy syntax for PHP 4
$cb3 = array(&$object, 'somePublicMethod');

これは、呼び出し可能な値を一般的に使用する安全な方法です。

if (is_callable($cb2)) {
    // Autoloading will be invoked to load the class "ClassName" if it's not
    // yet defined, and PHP will check that the class has a method
    // "someStaticMethod". Note that is_callable() will NOT verify that the
    // method can safely be executed in static context.

    $returnValue = call_user_func($cb2, $arg1, $arg2);
}

最新のPHPバージョンでは、上記の最初の3つの形式をとして直接呼び出すことができます$cb()。上記すべてcall_user_funccall_user_func_arrayサポートします。

参照:http : //php.net/manual/en/language.types.callable.php

注意事項/注意事項:

  1. 関数/クラスの名前空間が指定されている場合、文字列には完全修飾名が含まれている必要があります。例えば['Vendor\Package\Foo', 'method']
  2. call_user_funcは参照による非オブジェクトの受け渡しをサポートしていないためcall_user_func_array、以降のPHPバージョンでは、コールバックをvarに保存して直接構文を使用できます$cb()
  3. __invoke()メソッドを持つオブジェクト(無名関数を含む)は「呼び出し可能」のカテゴリーに分類され、同じように使用できますが、私はこれらを従来の「コールバック」という用語に関連付けていません。
  4. レガシーcreate_function()はグローバル関数を作成し、その名前を返します。これはラッパーでeval()あり、代わりに無名関数を使用する必要があります。

確かに、関数を使用するのが適切な方法です。変数を使用してからそれを呼び出すだけの場合、受け入れられた回答で提案されているようにクールですが、醜く、コードでうまくスケーリングできません。
icco 2009

4
受け入れた回答を変更しました。コメントに同意して、これは素晴らしい答えです。
Nick Stinemates

'someGlobalFunction'確かに定義された関数であることを回答で指摘することは、Pythonプログラミングの読者に役立つでしょう。
TMOTTM 2013

1
PHP 5.3以降、クロージャーがあります。Bartvan Heukelomの回答を参照してください。これは、このすべての従来の混乱よりもはるかに単純で「標準」です。
本当に素敵な2015

はい、私は私の回答で匿名関数について言及しましたが、OPは「コールバック」(2008年)を要求し、これらの古いスタイルのコールバックは、多くのPHPコードベースでまだ非常に多く使用されています。
Steve Clay

74

PHP 5.3では、これを行うことができます。

function doIt($callback) { $callback(); }

doIt(function() {
    // this will be done
});

最後にそれを行うための素晴らしい方法。コールバックは素晴らしいので、PHPへの素晴らしい追加です。


1
これが一番の答えである必要があります。
GROVER。

30

コールバックの実装はそのように行われます

// This function uses a callback function. 
function doIt($callback) 
{ 
    $data = "this is my data";
    $callback($data); 
} 


// This is a sample callback function for doIt(). 
function myCallback($data) 
{ 
    print 'Data is: ' .  $data .  "\n"; 
} 


// Call doIt() and pass our sample callback function's name. 
doIt('myCallback');

表示:データは:これは私のデータです


21
何てことだ。それは標準ですか?それはひどい!
Nick Retallack

上記のように、他にもいくつかの方法があります。本当に同じだと思いました。
Nick Stinemates

3
@ニック・レタラック、私はそれについて何がひどいのかわかりません。JavaScriptやC#など、私が知っている言語の場合、それらすべてがそのようなパターンでコールバック関数を構築できます。JavaScirptとC#から来た私は、call_user_func()に慣れていません。PHPに適応する必要があるように感じますが、その逆ではありません。
アントニー

4
@Antony文字列がこの言語の関数ポインタであるという事実に反対していました。3年前にそのコメントを投稿したので、今ではかなり慣れていますが、私が知っている言語(シェルスクリプト以外)はPHPだけだと思います。
Nick Retallack

1
@Antony私はJavaScriptで使用するのと同じ構文を使用することを好みます。call_user_func()そのため、動的に関数を呼び出してコールバックを実行できる構文がある場合に、なぜ人々が使いたいのかさえわかりません。仰るとおりです!
botenvouwer 2013

9

私が最近見つけた気の利いたトリックの1つは、PHPを使用create_function()して、1回限りの使用のための匿名/ラムダ関数を作成することです。それはのようなPHPの機能のために便利ですarray_map()preg_replace_callback()またはusort()カスタム処理のためのその使用のコールバック。裏で行うように見えますが、eval()それでもPHPを使用するための優れた関数型の方法です。


6
残念ながら、ガベージコレクターはこの構成でうまく機能せず、潜在的なメモリリークが発生します。パフォーマンスが足りない場合は、create_function()を使用しないでください。
fuxia

1
痛い。ヘッドアップをありがとう。
yukondude 2010年

PHP 7.4バージョン(矢印関数)で回答を更新し、廃止予定に関する警告を追加しcreate_function()ますか?
ダーマン


7

呼び出しが有効であることを確認する必要があります。たとえば、特定の関数の場合は、その関数が存在するかどうかを確認する必要があります。

function doIt($callback) {
    if(function_exists($callback)) {
        $callback();
    } else {
        // some error handling
    }
}

コールバックが関数ではなく、オブジェクトとメソッドを保持する配列である場合はどうなりますか?
d -_- b

3
どちらかと言えばis_callable( $callback )
Roko C. Buljan 2017年

1
どちらも良い提案です-コールバックを行う方法の特定の実装を確認する必要があります。存在しないものを呼び出すと致命的となることを警告することを望んでいました。私は答えをより一般的にしました
SeanDowney 2017

5

create_functionクラスの中で私のために働きませんでした。私は使用しなければなりませんでしたcall_user_func

<?php

class Dispatcher {
    //Added explicit callback declaration.
    var $callback;

    public function Dispatcher( $callback ){
         $this->callback = $callback;
    }

    public function asynchronous_method(){
       //do asynch stuff, like fwrite...then, fire callback.
       if ( isset( $this->callback ) ) {
            if (function_exists( $this->callback )) call_user_func( $this->callback, "File done!" );
        }
    }

}

次に、使用するには:

<?php 
include_once('Dispatcher.php');
$d = new Dispatcher( 'do_callback' );
$d->asynchronous_method();

function do_callback( $data ){
   print 'Data is: ' .  $data .  "\n";
}
?>

[編集]欠落していた括弧を追加。また、コールバック宣言を追加しましたが、私はそれを好みます。


1
Dispatcherクラスは、$ this-> callback = $ callbackが機能するための属性を必要としませんか?
James P.

@james poulson:PHPは動的言語なので、機能します。しかし、私は怠惰でした。私は通常、プロパティを宣言し、みんなの生活を楽にします。あなたの質問で、私はそのコードをもう一度見て、構文エラーを見つけました。ありがとう
goliatone 2011

これが可能であることを知りませんでした。答えてくれてありがとう:)。
James P.

Dispatcherオブジェクトを作成して非同期メソッドを呼び出す前に、do_callback関数を宣言する方が安全ではありませんか?
イジェクタメンタ2016年

3

create_function()はphpで使用するたびにうんざりしています。

パラメータは、カンマで区切られた文字列で、文字列内の関数本体全体です。

残念ながら、これは名前付き関数を作成しても問題がない場合の唯一の選択肢です。


1
そしてもちろん、それはランタイム文字列evalなので、有効な構文やその他のコンパイル時にチェックされません。
ホブ

この回答は過去2年間古くなっています。create_function()は非推奨になりました。使用しないでください。
ダーマン

2

PHP < 5.4との互換性を壊すことを気にしない人のために、型ヒントを使用してよりクリーンな実装にすることをお勧めします。

function call_with_hello_and_append_world( callable $callback )
{
     // No need to check $closure because of the type hint
     return $callback( "hello" )."world";
}

function append_space( $string )
{
     return $string." ";
}

$output1 = call_with_hello_and_append_world( function( $string ) { return $string." "; } );
var_dump( $output1 ); // string(11) "hello world"

$output2 = call_with_hello_and_append_world( "append_space" );
var_dump( $output2 ); // string(11) "hello world"

$old_lambda = create_function( '$string', 'return $string." ";' );
$output3 = call_with_hello_and_append_world( $old_lambda );
var_dump( $output3 ); // string(11) "hello world"

警告 create_function()は、PHP 7.2.0で廃止されました。この機能に依存することはお勧めできません。
ダーマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.