19

これは私を非常に混乱させ、この質問に対する答えを見つけることができないようです. 明確でシンプルな説明がいいでしょう。

4

2 に答える 2

26

は、クロージャ関数が作成された時点で変数use statementをキャプチャします。

通常の関数引数は、関数が呼び出されたときにを取得します。

variableとそこを区別したことに注意してくださいvalue

function makeAnAdder($leftNum) {
    // Notice that *each time* this makeAnAdder function gets called, we 
    // create and then return a brand new closure function.
    $closureFunc = function($rightNum) use ($leftNum) {
        return $leftNum + $rightNum;
    };

    return $closureFunc;
}

$add5to = makeAnAdder(5);
$add7to = makeAnAdder(7);

echo $add5to(10); // 15
echo $add7to(1); // 8

関数の「ソースコード」を検査する方法があれば、次の$add5toようになります。

function($rightNum) {
    return 5 + $rightNum;
}

$leftNumの値がクロージャー関数によって記憶されたと言えると思います。

ある時点で変数が持っていたのコピーだけでなく、 を変数use statement保持できることをさらに強調したいと思います。私の考えを明確にするために、変数を小さな箱と考えてください。この箱には、いつでも単一の値を入れることができ、その値を変更することができます。また、そのボックスを指す別の変数を作成して、ボックス内の値を更新したり、現在の値を読み取ったりすることができます。reference

通常、関数内で作成されたローカル変数は、関数が戻ると存在しなくなります。しかし、クロージャー関数はその変数への参照を維持し、関数が戻った後でもそのローカル変数を存続させることができます。これがクロージャー関数の真の力です。ごくわずかなコードで、クラス (インスタンス変数) の特定の動作を模倣できます。

これはより高度な例です。動作の詳細を理解するには、ある程度深く考える必要があります。

function makeBankAccount() {
    // Each time this makeBankAccount func is called, a new, totally
    // independent local variable named $balance is created.
    $balance = 0;

    // Also, on each call we create 2 new closure functions, $modifyBalance, and $getBalance
    // which will hold a reference to the $balance variable even after makeBankAccount returns.
    $modifyBalance = function($amount) use (&$balance) {
        $balance += $amount;
    };

    $getBalance = function() use (&$balance) {
        return $balance;
    };

    // return both closure functions.
    return ['modifyBalance' => $modifyBalance, 'getBalance' => $getBalance];
}

// Let's prove that bank1 works by adding 5 to the balance by using the first
// function, then using the other function to get the balance
// from the same internal variable.
$bank1 = makeBankAccount();
$bank1['modifyBalance'](5);
echo $bank1['getBalance'](); // 5 - it works.

// Now let's make another bank to prove that it has it's own independent internal $balance variable.
$bank2 = makeBankAccount();
$bank2['modifyBalance'](10);
echo $bank2['getBalance'](); // 10 - as expected. It would have printed 15 if bank2 shared a variable with bank1.

// Let's test bank1 one more time to be sure that bank2 didn't mess with it.
echo $bank1['getBalance'](); // 5 - still 5, as expected.

この例では参照演算子 を使用していることにお気づきかもしれません。&まだそれらに慣れていない場合は、参照が理解しにくいことが知られていることを知っておいてください。とはいえ、この投稿自体がほとんど意味をなすことを願っています。

于 2012-05-21T21:51:59.613 に答える
24

クロージャは、それ自体の環境で評価される関数であり、関数が呼び出されたときにアクセスできる1つ以上のバインドされた変数があります。それらは関数型プログラミングの世界から来ており、そこでは多くの概念が働いています。クロージャはラムダ関数に似ていますが、クロージャが定義されている外部環境からの変数と対話する機能があるという意味でよりスマートです。

use()キーワードを使用すると、関数環境の外部、関数の内部から変数をインポートできます。外部環境からインポートする変数は、クロージャ関数定義のuse句で指定します。デフォルトでは、値で渡されます。したがって、関数にパラメーターがないとしますが、既に持っている変数を使用する必要はありません。

$string = "Hello World!";
$closure = function() use ($string) { echo $string; };

これは、他の場所でコールバックとして使用する必要があり、定義されたパラメーターのみを持つことができる関数を作成する必要がある場合に役立ちます。use()キーワードを使用すると、関数引数として渡す変数に加えて、他の変数を使用できます。たとえば、php.netの例:http://php.net/manual/en/functions.anonymous.php

public function getTotal($tax)
    {
        $total = 0.00;

        $callback =
            function ($quantity, $product) use ($tax, &$total)
            {
                $pricePerItem = constant(__CLASS__ . "::PRICE_" .
                    strtoupper($product));
                $total += ($pricePerItem * $quantity) * ($tax + 1.0);
            };

        array_walk($this->products, $callback);
        return round($total, 2);
    }

array_walkはその量しか許可しないため、$callbackには2つのパラメーターのみが必要です。

通常、funcnameは2つのパラメーターを取ります。配列パラメーターの値が最初で、キー/インデックスが2番目です。

では、何ができるでしょうか。use()$ callbackのスコープではないが、呼び出されている環境のスコープ内にある他の変数を追加するために呼び出します。

于 2012-05-21T21:33:05.883 に答える