Los closures en PHP, disponibles desde la versión 5.3, permiten crear funciones anónimas que pueden capturar variables de su entorno. Esta característica es fundamental para escribir código más modular y reutilizable.
Funciones Anónimas
Las funciones anónimas, o closures, se definen sin un nombre y se asignan a una variable para su uso. A continuación, un ejemplo básico:
$miFuncion = function() {
// Cuerpo de la función
};
Estas funciones pueden aceptar parámetros y ser invocadas de manera similar a las funciones regulares:
$saludar = function($nombre) {
echo "Hola, $nombre";
};
$saludar("Mundo");
// Salida: Hola, Mundo
PHP también ofrecía la función create_function para crear funciones anónimas, pero su uso con cadenas de texto hacía el código menos legible y difícil de mantener.
Implementación de Closures
Los closures se implementan pasando funciones aónimas como argumentos o devolviéndolas desde otras funciones. Aquí hay tres ejemplos ilustrativos:
// Ejemplo 1: Definir y llamar a un closure dentro de una función
function mostrarSaludo() {
$closure = function($texto) {
echo $texto;
};
$closure("Texto de ejemplo");
}
mostrarSaludo();
// Ejemplo 2: Devolver un closure desde una función
function obtenerFuncionSaludo() {
$closure = function($texto) {
echo $texto;
};
return $closure;
}
$miFuncion = obtenerFuncionSaludo();
$miFuncion("Texto de ejemplo");
// Ejemplo 3: Pasar un closure como argumento
function ejecutarFuncion($callback) {
$callback("Texto de ejemplo");
}
$miClosure = function($texto) {
echo $texto;
};
ejecutarFuncion($miClosure);
// También se puede pasar directamente un closure anónimo
ejecutarFuncion(function($texto) {
echo $texto;
});
La Palabra Clave USE para Catpurar Variables
Por defecto, los closures no tienen acceso a variables del ámbito externo. Para incluir estas variables, se utiliza la palabra clave use. Observa este ejemplo:
function calcularPresupuesto() {
$montoLocal = 100;
$montoExtranjero = 150;
$closure = function() use ($montoLocal) {
echo "Monto local: $montoLocal\n";
// Intentar usar $montoExtranjero causará un error
echo "Monto extranjero: $montoExtranjero";
};
$closure();
}
calcularPresupuesto();
// Salida:
// Monto local: 100
// Error: $montoExtranjero no definido
Si se intenta modificar la variable capturada por use, el cambio no afecta a la variable original, ya que se pasa una copia:
function incrementarMonto() {
$monto = 10;
$closure = function() use ($monto) {
echo "Dentro del closure: $monto\n";
$monto += 5;
};
$closure();
echo "Fuera del closure: $monto";
}
incrementarMonto();
// Salida:
// Dentro del closure: 10
// Fuera del closure: 10
Para trabajar con la variable original, se usa la referencia con el operador &:
function ajustarMonto() {
$monto = 10;
$closure = function() use (&$monto) {
echo "Valor inicial: $monto\n";
$monto += 5;
};
$closure();
echo "Valor ajustado: $monto";
}
ajustarMonto();
// Salida:
// Valor inicial: 10
// Valor ajustado: 15
Al devolver un closure desde una función, este retiene las variables capturadas por use, formando un closure que persiste con su propio estado:
function crearContador() {
$contador = 0;
$incrementar = function() use (&$contador) {
$contador++;
echo "Contador: $contador\n";
};
return $incrementar;
}
$miContador = crearContador();
$miContador();
$miContador();
// Salida:
// Contador: 1
// Contador: 2
Los closures son útiles en diversas situaciones, como al usar funciones de callback en PHP, por ejemplo, array_map o preg_replace_callback, donde se puede definir la lógica inline sin necesidad de declarar funciones separadas.