Frage an anonymous-function, php, closures – Was ist der Unterschied zwischen den Abschlussparametern und dem Schlüsselwort 'use'?

18

Das hat mich sehr verwirrt und ich kann scheinbar keine Antwort auf diese Frage finden. Eine klare und einfache Klärung wäre schön.

Ich denke, Sie haben die falsche Antwort gewählt Pmpr

Deine Antwort

2   die antwort
21

die in einer eigenen Umgebung ausgewertet wird, die eine oder mehrere gebundene Variablen enthält, auf die beim Aufruf der Funktion zugegriffen werden kann. Sie kommen aus der funktionalen Programmierwelt, in der eine Reihe von Konzepten im Spiel sind. Verschlüsse sind wie Lambda-Funktionen, aber intelligenter in dem Sinne, dass sie mit Variablen von außerhalb der Umgebung interagieren können, in der der Verschluss definiert ist.

Mit dem Schlüsselwort use () können Sie Variablen von außerhalb der Funktionsumgebung innerhalb der Funktion importieren. Aus der externen Umgebung zu importierende Variablen werden in der use-Klausel der Closure-Funktionsdefinition angegeben. Standardmäßig werden sie als Wert übergeben. Nehmen wir also an, die Funktion hat keine Parameter, aber Sie möchten keine Variable verwenden, die Sie bereits haben.

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

Dies ist nützlich, wenn Sie eine Funktion erstellen müssen, die als Rückruf an einer anderen Stelle verwendet werden muss und nur definierte Parameter haben kann. Mit dem Schlüsselwort use () können Sie zusätzlich zu den Variablen, die Sie als Funktionsargumente übergeben, weitere Variablen verwenden. Zum Beispiel auf dem php.net Beispiel: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);
    }

$ callback darf nur zwei Parameter haben, da array_walk nur so viel zulässt:

In der Regel nimmt funcname zwei Parameter an. Der Wert des Array-Parameters ist der erste und der Schlüssel / Index der zweite.

Also was können wir tun? Wir nennenuse() um andere Variablen hinzuzufügen, die nicht dem Gültigkeitsbereich von $ callback entsprechen, sondern dem Gültigkeitsbereich der Umgebung, in der es aufgerufen wird.

Das ergibt für mich immer noch keinen Sinn. Wie ist es anders als$closure = function($string) { echo $string; };? Seralize
@Seralize: Ja. Damit können Sie der Funktion mehr Kontext hinzufügen, ohne die Parameter zu ändern. Stanislav Palatnik
Auch was @chris anbelangt! Stanislav Palatnik
@Seralize: Es ist der springende Punkt von aSchließung. Es hat nichts mit "Parameterfluss" oder was auch immer zu tun. Was Sie später angegeben haben, ist eine Funktion, die immer ihr Argument ausgibt, was nicht interessant ist. Mit dem Ausdruck von früher können wir eine Funktion erstellen, die "foo" druckt, oder eine Funktion, die "bar" druckt, oder irgendetwas anderes; und wir tun dies, ohne tatsächlich verschiedene Funktionen zu schreiben; Diese eine Codezeile erstellt bei jeder Ausführung eine Funktion mit neuem Verhalten (abhängig vom Wert der erfassten Variablen) - als ob Sie manuell separate Funktionen für sie geschrieben hätten. Das ist der unterschied newacct
25

use statement erfasst dieVariable zum Zeitpunkt derSchließfunktion wird erstellt.

Regelmäßige Funktionsargumente erfassen dieWert wenn die Funktion istnamens.

Beachten Sie, dass ich unterschieden habe zwischenvariable undvalue Dort.

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

Wenn es eine Möglichkeit gäbe, den "Quellcode" der$add5to Funktion würde es so aussehen:

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

Ich denke, Sie könnten den Wert von irgendwie sagen$leftNum wurde von der Schließfunktion erinnert.

Ich möchte weiter betonen, dass dieuse statement ermöglicht es Ihnen, eine zu pflegenreference zu einemVariableund nicht nur eine Kopie derWert dass die Variable irgendwann hatte. Um meine Idee zu verdeutlichen: Stellen Sie sich eine Variable als eine kleine Box vor, die jederzeit einen einzelnen Wert enthalten kann, und dieser Wert kann geändert werden. Sie können auch eine andere Variable auf dieses Feld verweisen, damit Sie den Wert im Feld aktualisieren oder den aktuellen Wert darin lesen können.

Normalerweise existiert eine lokale Variable, die in einer Funktion erstellt wird, nicht mehr, nachdem die Funktion zurückgegeben wurde. Eine Closure-Funktion kann jedoch einen Verweis auf diese Variable beibehalten und dafür sorgen, dass diese lokale Variable auch nach der Rückkehr der Funktion verwendet wird. Dies ist die wahre Stärke von Closure-Funktionen. Hiermit können Sie bestimmte Verhaltensweisen einer Klasse (Instanzvariablen) mit nur einem winzigen Code nachahmen.

Hier ist ein erweitertes Beispiel, das einige tiefgreifende Überlegungen erfordert, um die feinen Details des Verhaltens zu verstehen.

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.

Du hast vielleicht bemerkt, dass ich das benutzt habeReferenzoperator & in diesem Beispiel. Wenn Sie noch nicht mit ihnen vertraut sind, wissen Sie nur, dass Referenzen bekanntermaßen schwer zu verstehen sind. Ich hoffe jedoch, dass dieser Beitrag für sich allein Sinn ergibt.

Diese Antwort verdient die akzeptierte Antwort zu sein Pmpr
Ja, einige dieser Dinge sind wirklich schwer zu verstehen, weil es so viele Indirektions- und Bewertungspunkte gibt. Ich werde eine Klarstellung hinzufügen, die hoffentlich hilft. goat
Das ist ein guter Punkt, an dem Sie angekommen sind. Ich habe eine Weile gebraucht, um zu verstehen, wie das geht$rightnum Parameter wurde aufgerufen, aber es macht jetzt Sinn. Seralize

Verwandte Fragen