39

このトピックは、PHP で __construct()、__get()、__set()、および __call() をいつ使用する必要がありますか? __construct__getおよび__set魔法のメソッド について説明します。

PHP 5.3 以降、 と呼ばれる新しい Magic Method があり__invokeます。この__invokeメソッドは、スクリプトがオブジェクトを関数として呼び出そうとすると呼び出されます。

このメソッドについて私が行った調査では、人々はそれを Java メソッドに例えています.run()- Interface Runnableを参照してください。

$obj(); これについて長い間懸命に考えてきましたが、あなたが電話をかける理由が思い浮かびません。$obj->function();

オブジェクトの配列を繰り返し処理していたとしても、実行したいメイン関数の名前はわかっています。

それで、__invoke魔法の方法は、「できるからといって、すべきだとは限らない」PHPのショートカットの別の例ですか、それともこれが実際に正しいことである場合がありますか?

4

7 に答える 7

35

この回答は 2009 年に書かれたため、少し古くなっています。

PHP では、他の言語のように関数ポインターを渡すことはできません。関数はPHPのファースト クラスではありません。関数がファーストクラスであるということは、主に、関数を変数に保存し、いつでも渡して実行できることを意味します。

メソッドは、__invokePHP が疑似ファーストクラス関数に対応できる方法です。

このメソッドを使用して、クロージャーまたは継続__invokeとして機能するクラスを渡すことができます。また、単純に渡すことができる関数として渡すこともできます。

関数型プログラミングの多くは、第一級関数に依存しています。通常の命令型プログラミングでさえ、この恩恵を受けることができます。

並べ替えルーチンがあり、さまざまな比較機能をサポートしたいとします。__invoke 関数を実装し、そのクラスのインスタンスをソート関数に渡すさまざまな比較クラスを使用できます。関数の名前を知る必要さえありません。

実際、クラスを渡したり、関数にメソッドを呼び出したりするようなことはいつでもできましたが、他の言語ほどきれいではありませんが、クラスを渡す代わりに「関数」を渡すことについて話すことができるようになりました。

于 2009-05-20T14:16:15.597 に答える
15

この機能は、主に 5.3 の新しいクロージャー機能をサポートするために存在すると考えています。クロージャーはClosureクラスのインスタンスとして公開され、直接呼び出すことができ$foo = $someClosure();ます。の実用的な利点は__invoke()、関数、インスタンス メソッド、または静的メソッドのいずれを参照しているかに応じて、文字列、オブジェクト、および配列の奇妙な組み合わせを使用するのではなく、標準のコールバック タイプを作成できるようになることです。

于 2009-05-20T14:15:22.027 に答える
5

特定のタイプのオブジェクトを扱っていることがわかっている場合と$obj();は対照的に、本当に呼び出すべきではありません。$obj->function();とはいえ、同僚に頭を悩ませたくない場合を除きます。

この__invoke方法は、さまざまな状況で活気づきます。特に、ジェネリック呼び出し可能オブジェクトを引数として提供することが期待される場合。

引数として callable のみを取るクラス (使用する必要があり、変更できない) にメソッドがあるとします。

$obj->setProcessor(function ($arg) {
    // do something costly with the arguments
});

ここで、時間のかかる操作の結果をキャッシュして再利用したり、以前に使用したその関数の引数にアクセスしたりしたいとします。分厚いことができる通常の閉鎖で。

// say what? what is it for?
$argList = [];

$obj->setProcessor(function ($arg) use (&$argList) {
    static $cache;
    // check if there is a cached result...
    // do something costly with the arguments
    // remember used arguments
    $argList[] = $arg;
    // save result to a cache
    return $cache[$arg] = $result;
});

他の場所からにアクセスする必要がある場合$argList、または停止したエントリのキャッシュを単純に消去する必要がある場合は、問題が発生します。

ここで__invoke救助に来ます:

class CachableSpecificWorker
{
    private $cache = [];

    private $argList = [];

    public function __invoke($arg)
    {
        // check if there is a cached result...

        // remember used arguments
        $this->argList[] = $arg;

        // do something costly with the arguments

        // save result to a cache
        return $this->cache[$arg] = $result;
    }

    public function removeFromCache($arg)
    {
        // purge an outdated result from the cache
        unset($this->cache[$arg]);
    }

    public function countArgs()
    {
        // do the counting
        return $resultOfCounting;
    }
}

上記のクラスを使用すると、キャッシュされたデータを簡単に操作できます。

$worker = new CachableSpecificWorker();
// from the POV of $obj our $worker looks like a regular closure
$obj->setProcessor($worker);
// hey ho! we have a new data for this argument
$worker->removeFromCache($argWithNewData);
// pass it on somewhere else for future use
$logger->gatherStatsLater($worker);

これは、概念を説明するための単純な例です。さらに進んで、一般的なラッパーとキャッシング クラスを作成することもできます。そして、はるかに。

于 2016-05-12T03:01:45.000 に答える
4

それは2つのことの組み合わせです。そのうちの 1 つを既に正しく識別しています。これは実際IRunnable、すべての「実行可能な」オブジェクトが同じメソッドを実装する Java のインターフェースとまったく同じです。Java では、メソッドの名前はrun; PHP では、メソッドの名前__invokeは であり、事前に特定のインターフェイス タイプを明示的に実装する必要はありません。

2 番目の側面は構文的な砂糖です。つまり、 を呼び出す代わりに$obj->__invoke()、メソッド名をスキップできるため、オブジェクトを直接呼び出しているように見えます$obj()

PHP がクロージャーを持つ重要な部分は最初の部分です。言語には、クロージャー オブジェクトを呼び出すための確立されたメソッドが必要です。シンタックス シュガーは、2 つのアンダースコア プレフィックスを持つすべての「特別な」関数の場合と同様に、見栄えを良くするための単なる方法です。

于 2009-05-20T14:24:35.893 に答える