2012-05-21 23 views

Respuesta

19

Un cierre es una función que se evalúa en su propio entorno, que tiene una o más variables enlazadas 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 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 desde el entorno externo se especifican en la cláusula de uso de la definición de la función de cierre. Por defecto, se pasan por valor. Digamos que la función no tiene parámetros, pero no quiere usar una variable que ya tenga.

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

Esto es útil cuando se necesita para crear una función de lo que debe ser utilizado como devolución de llamada en otro lugar, y sólo se han definido los parámetros. La palabra clave use() le permite usar otras variables además de las que pasa como argumento de la función. Por ejemplo, en el ejemplo 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); 
    } 

$ devolución de llamada sólo debe tener dos parámetros, porque array_walk sólo permitirá que gran parte:

Típicamente, nombre_func recibe dos parámetros. El valor del parámetro de matriz es el primero, y el segundo clave/índice.

Entonces, ¿qué podemos hacer? Llamamos a use() añadir otras variables que no son alcance los $ de devolución de llamada, pero en alcance del entorno que se está llamando en.

+0

Todavía no tiene sentido para mí. ¿Cómo es diferente de '$ closure = function ($ string) {echo $ string; }; '? – Seralize

+1

@Seralize: Lo siento, actualicé mi ejemplo. Básicamente, algunas funciones en PHP permiten callbacks (como array_walk, array_map, etc. que tienen parámetros predefinidos. En estos casos, puedes llamar a use() para agregar otras variables que de otra manera no serían posibles de usar en una devolución de llamada. –

+0

Eso tiene sentido Así que la palabra clave 'use()' es básicamente solo una manera de importar variables en un cierre sin estropear el "flujo de parámetros", ya que los parámetros que no están configurados darán un error? – Seralize

24

El use statement capta la variable en el momento de la función cierre se crea.

Los argumentos de la función normal capturan el valor cuando la función es llamada.

Tenga en cuenta que he diferenciado entre variable y allí.

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 manera de inspeccionar el, um, "código fuente" de la función $add5to, se vería así:

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

supongo que se podría decir un poco el valor de $leftNum fue recordado por la función de cierre.

Quiero destacar además que la use statement le permite mantener un reference a una variable , y no sólo una copia del valorque la variable tuvo en algún momento. Para aclarar mi idea: piense en una variable como una pequeña caja, que puede contener un único valor en cualquier instante en el tiempo, y ese valor se puede cambiar.Y puede hacer que otro punto variable sea ese cuadro, para 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. Sin embargo, una función de cierre puede mantener una referencia a esa variable y hacer que la variable local permanezca activa incluso después de que la función regrese, y esta es la verdadera potencia de las funciones de cierre. Te 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 llevar un pensamiento profundo para comprender los detalles 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. 

Usted puede haber notado he utilizado la reference operator& en este ejemplo. Si todavía no estás familiarizado con ellos, solo debes saber que las referencias son difíciles de entender. Aunque, espero que esta publicación tenga más sentido por sí misma.

+0

Ese es un buen punto para llegar allí. Me tomó un tiempo entender cómo se llamó el parámetro '$ rightnum', pero ahora tiene sentido. – Seralize

+0

Ya, algunas de estas cosas son realmente difíciles de entender porque hay tantos puntos de indirección y evaluación. Añadiré una aclaración que espero ayude. – goat

+2

Esta respuesta merece ser la respuesta aceptada – Trix

Cuestiones relacionadas