Pregunta sobre php, closures, anonymous-function – ¿Cuál es la diferencia entre los parámetros de cierre y la palabra clave 'uso'?

18

Esto me ha confundido mucho y parece que no puedo encontrar una respuesta a esta pregunta. Una aclaración clara y simple sería agradable.

Creo que has elegido la respuesta equivocada. Pmpr

Tu respuesta

2   la respuesta
25

losuse statement captura elvariable en el momento else crea la funcion de cierre.

Los argumentos de funciones regulares capturan elvalor cuando la funcion esllamado.

Tenga en cuenta que he diferenciado entrevariable yvalue ahí.

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

Si hubiera una forma de inspeccionar, um, el "código fuente" del$add5to función, se vería así:

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

Supongo que podrías decir el valor de$leftNum Fue recordado por la función de cierre.

Quiero enfatizar aún más que lause statement le permite mantener unreference a unvariable, y no solo una copia de lavalor Que la variable tenía en algún momento. Para aclarar mi idea: piense en una variable como si fuera una pequeña caja, que puede contener un solo valor en cualquier instante en el tiempo, y ese valor se puede cambiar. Y, puede hacer que otra variable apunte a ese cuadro, de modo que pueda actualizar el valor en el cuadro, o leer el valor actual en él.

Normalmente, una variable local que se crea dentro de una función deja de existir después de que la función retorna. Pero, una función de cierre puede mantener una referencia a esa variable y hacer que esa variable local viva incluso después de que la función regrese, y este es el verdadero poder de las funciones de cierre. Le permite imitar ciertos comportamientos de una clase (variables de instancia), con solo un poquito de código.

Aquí hay un ejemplo más avanzado, que podría requerir un pensamiento profundo para comprender los detalles finos del comportamiento.

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.

Te habrás dado cuenta de que usé eloperador de referencia & en este ejemplo. Si aún no estás familiarizado con ellos, debes saber que las referencias son difíciles de entender. Aunque, espero que este post tenga sentido en su mayor parte por sí mismo.

Ya, algunas de estas cosas son realmente difíciles de entender porque hay muchos puntos de indirección y evaluación. Añadiré una aclaración que espero que ayude. goat
Ese es un buen punto que tienes ahí. Me tomó un tiempo entender cómo$rightnum parámetro llamado, pero tiene sentido ahora. Seralize
Esta respuesta merece ser la respuesta aceptada. Pmpr
21

Un cierre es una función que se evalúa en su propio entorno, que tiene una o más variables vinculadas a las que se puede acceder cuando se llama a la función. Vienen del mundo de la programación funcional, donde hay una serie de conceptos en juego. Los cierres son como las funciones lambda, pero más inteligentes en el sentido de que tienen la capacidad de interactuar con las variables del entorno externo donde se define el cierre.

La palabra clave use () le permite importar variables desde fuera del entorno de la función, dentro de la función. Las variables a importar del entorno exterior se especifican en la cláusula de uso de la definición de la función de cierre. Por defecto, se pasan por valor. Entonces, digamos que la función no tiene parámetros, pero usted no va a usar una variable que ya tiene.

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

Esto es útil cuando necesita crear una función que debe usarse como devolución de llamada en otro lugar y solo puede tener parámetros definidos. La palabra clave use () le permite usar otras variables además de las que pasa como argumentos de función. Por ejemplo en el ejemplo de 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);
    }

$ callback solo debe tener dos parámetros, porque array_walk solo permitirá eso:

Normalmente, funcname toma dos parámetros. El valor del parámetro de matriz es el primero, y la clave / índice segundo.

Entonces, ¿qué podemos hacer? Nosotros llamamosuse() para agregar otras variables que no sean el alcance de $ callback, sino en el ámbito del entorno en el que se está solicitando.

En cierto modo, parece inútil, pero en otro siempre habrá momentos en que cosas tan pequeñas pueden ayudar a resolver un problema. ¡Gracias por aclararme! Seralize
@Seralize: Es el punto entero de uncierre. No tiene nada que ver con el "flujo de parámetros" o lo que sea. Lo que dio más tarde es una función que siempre genera su argumento, lo que no es interesante. Con la expresión anterior, podemos hacer una función que imprima "foo", o una función que imprima "barra", o cualquier otra cosa; y lo hacemos sin escribir realmente diferentes funciones; esa línea de código, cada vez que se ejecuta, creará una función con nuevo comportamiento (dependiendo del valor de la variable capturada), como si escribiera manualmente funciones separadas para ellos. Esa es la diferencia. newacct
Todavía no tiene sentido para mí. ¿Cómo es diferente de$closure = function($string) { echo $string; };? Seralize
También lo que mencionó Chris! Stanislav Palatnik

Preguntas relacionadas