variable pass example ejemplos closure php closures

pass - php function use external variable



En PHP, ¿qué es un cierre y por qué utiliza el identificador de "uso"? (5)

Estoy revisando algunas características de PHP 5.3.0 y encontré un código en el sitio que parece bastante divertido:

public function getTotal($tax) { $total = 0.00; $callback = /* This line here: */ 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); }

Como uno de los ejemplos sobre funciones anónimas .

¿Alguien sabe sobre esto? Cualquier documentación? Y parece malvado, ¿debería ser usado alguna vez?


Así es como PHP expresa un closure . Esto no es para nada malo y, de hecho, es bastante poderoso y útil.

Básicamente, lo que esto significa es que está permitiendo que la función anónima "capture" las variables locales (en este caso, $tax y una referencia a $total ) fuera de su alcance y preserven sus valores (o en el caso de $total la referencia a $total sí mismo) como estado dentro de la propia función anónima.


La function () use () {} es el cierre para PHP, debe use para incluir la variable de la function principal.

<?php $message = "hello/n"; $example = function () { echo $message; }; // Notice: Undefined variable: message $example(); $example = function () use ($message) { echo $message; }; // "hello" $example(); // Inherited variable''s value is from when the function is defined, not when called $message = "world/n"; // "hello" $example(); // Inherit by-reference $message = "hello/n"; $example = function () use (&$message) { echo $message; }; // "hello" $example(); // The changed value in the parent scope is reflected inside the function call $message = "world/n"; // "world" $example(); // Closures can also accept regular arguments $example = function ($arg) use ($message) { echo $arg . '' '' . $message; }; // "hello world" $example("hello");


Los cierres son hermosos! resuelven muchos problemas que vienen con funciones anónimas y hacen posible un código realmente elegante (al menos mientras hablemos de php).

Los programadores de javascript usan cierres todo el tiempo, a veces incluso sin saberlo, porque las variables enlazadas no están definidas explícitamente, para eso es "uso" en php.

Hay mejores ejemplos del mundo real que el anterior. digamos que tiene que ordenar una matriz multidimensional por un subvalor, pero la clave cambia.

<?php function generateComparisonFunctionForKey($key) { return function ($left, $right) use ($key) { if ($left[$key] == $right[$key]) return 0; else return ($left[$key] < $right[$key]) ? -1 : 1; }; } $myArray = array( array(''name'' => ''Alex'', ''age'' => 70), array(''name'' => ''Enrico'', ''age'' => 25) ); $sortByName = generateComparisonFunctionForKey(''name''); $sortByAge = generateComparisonFunctionForKey(''age''); usort($myArray, $sortByName); usort($myArray, $sortByAge); ?>

advertencia: código no probado (no tengo instalado php5.3 atm), pero debería parecerse a algo así.

hay un inconveniente: muchos desarrolladores de php pueden estar un poco indefensos si los confrontas con cierres.

para entender más la amabilidad de los cierres, te daré otro ejemplo, esta vez en javascript. Uno de los problemas es el alcance y la asincronía inherente del navegador. especialmente, si se trata de window.setTimeout(); (o -intervalo). entonces, pasa una función a setTimeout, pero realmente no puede dar ningún parámetro, ¡porque los parámetros ejecutan el código!

function getFunctionTextInASecond(value) { return function () { document.getElementsByName(''body'')[0].innerHTML = value; // "value" is the bound variable! } } var textToDisplay = prompt(''text to show in a second'', ''foo bar''); // this returns a function that sets the bodys innerHTML to the prompted value var myFunction = getFunctionTextInASecond(textToDisplay); window.setTimeout(myFunction, 1000);

myFunction devuelve una función con un tipo de parámetro predefinido!

Para ser honesto, me gusta mucho más PHP desde 5.3 y funciones / cierres anónimos. Los espacios de nombres pueden ser más importantes, pero son mucho menos atractivos .


Una respuesta más sencilla.

function ($quantity) use ($tax, &$total) { .. };

  1. El cierre es una función asignada a una variable, por lo que puede pasarla
  2. Un cierre es un espacio de nombres separado, normalmente, no puede acceder a las variables definidas fuera de este espacio de nombres. Llega la palabra clave de uso :
  3. el uso le permite acceder (usar) las variables siguientes dentro del cierre.
  4. El uso es de unión temprana. Eso significa que los valores de las variables están COPIADOS al DEFINIR el cierre. Por lo tanto, modificar $tax dentro del cierre no tiene efecto externo, a menos que sea un puntero, como lo es un objeto.
  5. Puede pasar variables como punteros en caso de &$total . De esta manera, la modificación del valor de $total TIENE UN EFECTO EXTERNO, cambia el valor de la variable original.
  6. Las variables definidas dentro del cierre tampoco son accesibles desde fuera del cierre.
  7. Los cierres y funciones tienen la misma velocidad. Sí, puedes usarlos en todos tus scripts.

Como @Mytskine señaló que probablemente la mejor explicación en profundidad es la RFC para cierres . (Avísale por esto)


Zupa hizo un gran trabajo al explicar los cierres con "uso" y la diferencia entre EarlyBinding y referenciar las variables que se "usan".

Así que hice un ejemplo de código con el enlace temprano de una variable (= copia):

<?php $a = 1; $b = 2; $closureExampleEarlyBinding = function() use ($a, $b){ $a++; $b++; echo "Inside /$closureExampleEarlyBinding() /$a = ".$a."<br />"; echo "Inside /$closureExampleEarlyBinding() /$b = ".$b."<br />"; }; echo "Before executing /$closureExampleEarlyBinding() /$a = ".$a."<br />"; echo "Before executing /$closureExampleEarlyBinding() /$b = ".$b."<br />"; $closureExampleEarlyBinding(); echo "After executing /$closureExampleEarlyBinding() /$a = ".$a."<br />"; echo "After executing /$closureExampleEarlyBinding() /$b = ".$b."<br />"; /* this will output: Before executing $closureExampleEarlyBinding() $a = 1 Before executing $closureExampleEarlyBinding() $b = 2 Inside $closureExampleEarlyBinding() $a = 2 Inside $closureExampleEarlyBinding() $b = 3 After executing $closureExampleEarlyBinding() $a = 1 After executing $closureExampleEarlyBinding() $b = 2 */ ?>

Ejemplo con referencia a una variable (observe el carácter ''&'' antes de la variable);

<?php $a = 1; $b = 2; $closureExampleReferencing = function() use (&$a, &$b){ $a++; $b++; echo "Inside /$closureExampleReferencing() /$a = ".$a."<br />"; echo "Inside /$closureExampleReferencing() /$b = ".$b."<br />"; }; echo "Before executing /$closureExampleReferencing() /$a = ".$a."<br />"; echo "Before executing /$closureExampleReferencing() /$b = ".$b."<br />"; $closureExampleReferencing(); echo "After executing /$closureExampleReferencing() /$a = ".$a."<br />"; echo "After executing /$closureExampleReferencing() /$b = ".$b."<br />"; /* this will output: Before executing $closureExampleReferencing() $a = 1 Before executing $closureExampleReferencing() $b = 2 Inside $closureExampleReferencing() $a = 2 Inside $closureExampleReferencing() $b = 3 After executing $closureExampleReferencing() $a = 2 After executing $closureExampleReferencing() $b = 3 */ ?>