En PHP, las funciones son ciudadanos de primera clase: se pueden asignar a variables, pasarse como argumentos y devolverse desde otras funciones. Los closures (funciones anónimas) y las arrow functions de PHP 7.4 son las dos formas principales de crear funciones inline, cada una con su propio mecanismo de captura de variables del scope circundante.
Closures básicos: funciones anónimas
<?php
// Asignar un closure a una variable
$saludar = function (string $nombre): string {
return "Hola, $nombre";
};
echo $saludar('Ana'); // Hola, Ana
// Como argumento de función
$numeros = [3, 1, 4, 1, 5, 9, 2, 6];
usort($numeros, function (int $a, int $b): int {
return $a <=> $b; // operador spaceship
});
// [1, 1, 2, 3, 4, 5, 6, 9]
?>
Capturar variables con use
<?php
$multiplicador = 3;
// Captura por valor (copia en el momento de definir el closure)
$porValor = function (int $n) use ($multiplicador): int {
return $n * $multiplicador;
};
$multiplicador = 10; // cambiar la variable original no afecta al closure
echo $porValor(5); // 15 (usa el valor 3 capturado al definir)
// Captura por referencia (&)
$contador = 0;
$incrementar = function () use (&$contador): void {
$contador++;
};
$incrementar();
$incrementar();
echo $contador; // 2 (se modifica la variable original)
?>
Arrow functions de PHP 7.4
Las arrow functions (fn) capturan automáticamente todas las variables del scope exterior por valor, sin necesitar use:
<?php
$iva = 0.21;
// Closure con use
$precioConIva1 = function (float $base) use ($iva): float {
return $base * (1 + $iva);
};
// Arrow function: captura $iva automáticamente
$precioConIva2 = fn(float $base): float => $base * (1 + $iva);
echo $precioConIva2(100.0); // 121.0
// Muy útil en callbacks de array_map, array_filter, usort
$precios = [10.0, 25.0, 50.0, 100.0];
$conIva = array_map(fn(float $p): float => $p * (1 + $iva), $precios);
// [12.1, 30.25, 60.5, 121.0]
$caros = array_filter($precios, fn(float $p): bool => $p > 20.0);
// [25.0, 50.0, 100.0]
?>
Closures como callbacks en funciones de array
<?php
$usuarios = [
['nombre' => 'Ana', 'edad' => 30, 'activo' => true],
['nombre' => 'Luis', 'edad' => 17, 'activo' => true],
['nombre' => 'Eva', 'edad' => 25, 'activo' => false],
['nombre' => 'Marcos', 'edad' => 22, 'activo' => true],
];
// Filtrar y transformar con arrow functions
$nombresAdultos = array_map(
fn(array $u): string => $u['nombre'],
array_filter(
$usuarios,
fn(array $u): bool => $u['activo'] && $u['edad'] >= 18
)
);
echo implode(', ', $nombresAdultos); // Ana, Marcos
// Ordenar por edad descendente
usort($usuarios, fn(array $a, array $b): int => $b['edad'] <=> $a['edad']);
?>
Closure::bind y bindTo: vincular a objetos
<?php
class Caja
{
private string $contenido = 'secreto';
}
// Vincular un closure a una instancia para acceder a propiedades privadas
$leer = Closure::bind(
function (): string { return $this->contenido; },
new Caja(),
Caja::class // contexto de la clase
);
echo $leer(); // secreto
// Útil en frameworks para inyectar comportamiento en objetos
$modificar = function (string $nuevo): void {
$this->contenido = $nuevo;
};
$closure = Closure::bind($modificar, new Caja(), Caja::class);
$caja = new Caja();
$cerrado = $closure->bindTo($caja, $caja);
// bindTo() crea una nueva copia vinculada a $caja
?>
Closures como estrategias de configuración
<?php
class Coleccion
{
public function __construct(private array $items) {}
public function filtrar(Closure $predicado): static
{
return new static(array_values(array_filter($this->items, $predicado)));
}
public function transformar(Closure $fn): static
{
return new static(array_map($fn, $this->items));
}
public function toArray(): array { return $this->items; }
}
$resultado = (new Coleccion([1, 2, 3, 4, 5, 6, 7, 8]))
->filtrar(fn(int $n): bool => $n % 2 === 0) // pares: [2,4,6,8]
->transformar(fn(int $n): int => $n ** 2) // cuadrados: [4,16,36,64]
->toArray();
?>
La documentación oficial de funciones anónimas en PHP y la de arrow functions detallan las diferencias de captura, los tipos de retorno implícitos y las restricciones sobre el uso de yield dentro de closures.
