PHP admitirá cierres de forma nativa en 5.3. Un cierre es bueno cuando desea una función local que solo se use para algún propósito pequeño y específico. El RFC para cierres da un buen ejemplo:
function replace_spaces ($text) {
$replacement = function ($matches) {
return str_replace ($matches[1], ' ', ' ').' ';
};
return preg_replace_callback ('/( +) /', $replacement, $text);
}
Esto le permite definir la replacement
función localmente en el interior replace_spaces()
, de modo que no:
1) Aborde el espacio
de nombres global 2) Hace que las personas tres años después se pregunten por qué hay una función definida globalmente que solo se usa dentro de otra función
Mantiene las cosas organizadas. Observe cómo la función en sí no tiene nombre, simplemente se define y se asigna como una referencia a $replacement
.
Pero recuerde, debe esperar a PHP 5.3 :)
También puede acceder a variables fuera de su alcance en un cierre utilizando la palabra clave use
. Considere este ejemplo.
$multiplier = 3;
$numbers = array(1,2,3,4);
array_walk($numbers, function($number) use($multiplier){
echo $number * $multiplier;
});
Aquí se ofrece una excelente explicación ¿Qué son las lambdas y los cierres de php?
Cuando necesitará una función en el futuro que realice una tarea que ha decidido ahora.
Por ejemplo, si lee un archivo de configuración y uno de los parámetros le dice que el
hash_method
algoritmo de su algoritmo es enmultiply
lugar desquare
, puede crear un cierre que se usará siempre que necesite aplicar un hash a algo.El cierre se puede crear en (por ejemplo)
config_parser()
; crea una función llamadado_hash_method()
usando variables locales paraconfig_parser()
(desde el archivo de configuración). Siempre quedo_hash_method()
se llama, tiene acceso a las variables en el ámbito local deconfig_parser()
aunque no se llame en ese ámbito.Un buen ejemplo hipotético con suerte:
function config_parser() { // Do some code here // $hash_method is in config_parser() local scope $hash_method = 'multiply'; if ($hashing_enabled) { function do_hash_method($var) { // $hash_method is from the parent's local scope if ($hash_method == 'multiply') return $var * $var; else return $var ^ $var; } } } function hashme($val) { // do_hash_method still knows about $hash_method // even though it's not in the local scope anymore $val = do_hash_method($val) }
fuente
Aparte de los detalles técnicos, los cierres son un requisito previo fundamental para un estilo de programación conocido como programación orientada a funciones. Un cierre se usa aproximadamente para lo mismo que usa un objeto en la programación orientada a objetos; Vincula datos (variables) junto con algún código (una función), que luego puede pasar a otro lugar. Como tales, tienen un impacto en la forma en que escribe programas o, si no cambia la forma en que escribe sus programas, no tienen ningún impacto en absoluto.
En el contexto de PHP, son un poco extraños, ya que PHP ya es pesado en el paradigma orientado a objetos basado en clases, así como en el antiguo procedimiento. Por lo general, los lenguajes que tienen cierres tienen un alcance léxico completo. Para mantener la compatibilidad con versiones anteriores, PHP no va a obtener esto, por lo que significa que los cierres serán un poco diferentes aquí que en otros lenguajes. Creo que todavía tenemos que ver exactamente cómo se utilizarán.
fuente
Me gusta el contexto proporcionado por la publicación de troelskn. Cuando quiero hacer algo como el ejemplo de Dan Udey en PHP, uso el patrón de estrategia OO. En mi opinión, esto es mucho mejor que introducir una nueva función global cuyo comportamiento se determina en tiempo de ejecución.
http://en.wikipedia.org/wiki/Strategy_pattern
También puede llamar a funciones y métodos usando una variable que contenga el nombre del método en PHP, lo cual es genial. por lo que otra versión del ejemplo de Dan sería algo como esto:
class ConfigurableEncoder{ private $algorithm = 'multiply'; //default is multiply public function encode($x){ return call_user_func(array($this,$this->algorithm),$x); } public function multiply($x){ return $x * 5; } public function add($x){ return $x + 5; } public function setAlgorithm($algName){ switch(strtolower($algName)){ case 'add': $this->algorithm = 'add'; break; case 'multiply': //fall through default: //default is multiply $this->algorithm = 'multiply'; break; } } } $raw = 5; $encoder = new ConfigurableEncoder(); // set to multiply echo "raw: $raw\n"; // 5 echo "multiply: " . $encoder->encode($raw) . "\n"; // 25 $encoder->setAlgorithm('add'); echo "add: " . $encoder->encode($raw) . "\n"; // 10
por supuesto, si desea que esté disponible en todas partes, puede hacer que todo esté estático ...
fuente
Un cierre es básicamente una función para la que escribe la definición en un contexto pero se ejecuta en otro contexto. Javascript me ayudó mucho a comprenderlos, porque se utilizan en JavaScript en todas partes.
En PHP, son menos efectivos que en JavaScript, debido a las diferencias en el alcance y la accesibilidad de las variables "globales" (o "externas") dentro de las funciones. Sin embargo, a partir de PHP 5.4, los cierres pueden acceder al objeto $ this cuando se ejecutan dentro de un objeto, esto los hace mucho más efectivos.
De esto se tratan los cierres, y debería ser suficiente para entender lo que está escrito arriba.
Esto significa que debería ser posible escribir una definición de función en algún lugar y usar la variable $ this dentro de la definición de función, luego asignar la definición de función a una variable (otros han dado ejemplos de la sintaxis), luego pasar esta variable a un objeto y llamarlo en el contexto del objeto, la función puede acceder y manipular el objeto a través de $ this como si fuera solo otro de sus métodos, cuando de hecho no está definido en la definición de clase de ese objeto, sino en otro lugar.
Si no está muy claro, no se preocupe, se aclarará una vez que comience a usarlos.
fuente
Básicamente, Closure son las funciones internas que tienen acceso a las variables externas y se utilizan como una función de devolución de llamada a una función anónima (funciones que no tienen ningún nombre).
<?php $param='ironman'; function sayhello(){ $param='captain'; $func=function () use ($param){ $param='spiderman'; }; $func(); echo $param; } sayhello(); ?> //output captain //and if we pass variable as a reference as(&$param) then output would be spider man;
fuente
$param='captain'
in funcsayhello()
es una variable local de funcsayhello()
.$param='ironman'
arribasayhello()
es la variable global. Si desea hacer solo una variable $ param en su script, debe llamar:global $param;
dentro desayhello()
funcAquí hay ejemplos de cierres en php
// Author: [email protected] // Publish on: 2017-08-28 class users { private $users = null; private $i = 5; function __construct(){ // Get users from database $this->users = array('a', 'b', 'c', 'd', 'e', 'f'); } function displayUsers($callback){ for($n=0; $n<=$this->i; $n++){ echo $callback($this->users[$n], $n); } } function showUsers($callback){ return $callback($this->users); } function getUserByID($id, $callback){ $user = isset($this->users[$id]) ? $this->users[$id] : null; return $callback($user); } } $u = new users(); $u->displayUsers(function($username, $userID){ echo "$userID -> $username<br>"; }); $u->showUsers(function($users){ foreach($users as $user){ echo strtoupper($user).' '; } }); $x = $u->getUserByID(2, function($user){ return "<h1>$user</h1>"; }); echo ($x);
Salida:
0 -> a 1 -> b 2 -> c 3 -> d 4 -> e 5 -> f A B C D E F c
fuente
Cierres:
MDN tiene la mejor explicación en mi opinión:
es decir, un cierre es una función con acceso a las variables que están en el ámbito principal. Un cierre nos permite crear funciones cómodamente sobre la marcha, ya que en algunas situaciones una función solo se necesita en un lugar (devoluciones de llamada, argumentos invocables).
Ejemplo:
$arr = [1,2,3,3]; $outersScopeNr = 2; // The second arg in array_filter is a closure // It would be inconvenient to have this function in global namespace // The use keyword lets us access a variable in an outer scope $newArr = array_filter($arr, function ($el) use ($outersScopeNr) { return $el === 3 || $el === $outersScopeNr; }); var_dump($newArr); // array (size=3) // 1 => int 2 // 2 => int 3 // 3 => int 3
fuente