Funciones Anónimas
Las funciones anónimas (también llamadas closures o lambdas) son funciones sin nombre que puedes almacenar en variables, pasar como argumentos o retornar desde otras funciones. Son fundamentales para la programación funcional en PHP.
¿Qué es una función anónima?
Una función anónima es una función que no tiene
nombre. Se define usando la palabra clave
function sin un identificador:
<?php
declare(strict_types=1);
// Función con nombre
function sumarNormal(int $a, int $b): int
{
return $a + $b;
}
// Función anónima asignada a una variable
$sumar = function (int $a, int $b): int {
return $a + $b;
};
// Llamar a la función anónima
echo $sumar(5, 3); // 8
// Puedes reasignar la variable a otra función
$sumar = function (int $a, int $b): int {
return $a + $b + 10; // Ahora suma 10 extra
};
echo $sumar(5, 3); // 18
Las funciones anónimas asignadas a variables terminan con punto y coma, ya que son una expresión de asignación.
Como callbacks
El uso más común de las funciones anónimas es como callbacks, funciones que se pasan como argumento a otras funciones:
<?php
declare(strict_types=1);
$numeros = [1, 2, 3, 4, 5];
// array_map con función anónima
$cuadrados = array_map(function (int $n): int {
return $n * $n;
}, $numeros);
print_r($cuadrados); // [1, 4, 9, 16, 25]
// array_filter con función anónima
$pares = array_filter($numeros, function (int $n): bool {
return $n % 2 === 0;
});
print_r($pares); // [1 => 2, 3 => 4]
// usort con función anónima
$personas = [
['nombre' => 'Ana', 'edad' => 25],
['nombre' => 'Luis', 'edad' => 30],
['nombre' => 'Eva', 'edad' => 22],
];
usort($personas, function (array $a, array $b): int {
return $a['edad'] <=> $b['edad'];
});
// Ordenado por edad ascendente
print_r($personas);
/*
[
['nombre' => 'Eva', 'edad' => 22],
['nombre' => 'Ana', 'edad' => 25],
['nombre' => 'Luis', 'edad' => 30],
]
*/
Capturar variables con use
Las funciones anónimas no tienen acceso
automático a las variables del ámbito donde se
definen. Usa use para capturar
variables:
<?php
declare(strict_types=1);
$multiplicador = 10;
// Sin use: la variable no está disponible
$sinUse = function (int $n): int {
// return $n * $multiplicador; // Error: undefined variable
return $n * 2;
};
// Con use: captura la variable
$conUse = function (int $n) use ($multiplicador): int {
return $n * $multiplicador;
};
echo $conUse(5); // 50
// Capturar múltiples variables
$base = 100;
$incremento = 5;
$calcular = function (int $cantidad) use ($base, $incremento): int {
return $base + ($cantidad * $incremento);
};
echo $calcular(3); // 115
Captura por valor vs por referencia
Por defecto, use captura por valor
(copia). Usa &
para capturar por referencia:
<?php
declare(strict_types=1);
// Captura por valor (copia)
$contador = 0;
$incrementarValor = function () use ($contador): int {
// Modifica la copia local, no el original
return ++$contador;
};
echo $incrementarValor(); // 1
echo $incrementarValor(); // 1 (siempre parte de 0)
echo $contador; // 0 (no cambió)
// Captura por referencia
$contadorRef = 0;
$incrementarRef = function () use (&$contadorRef): int {
return ++$contadorRef;
};
echo $incrementarRef(); // 1
echo $incrementarRef(); // 2
echo $incrementarRef(); // 3
echo $contadorRef; // 3 (sí cambió)
Usa captura por referencia con cuidado. Es útil para acumuladores o cuando necesitas modificar estado externo, pero puede hacer el código difícil de seguir.
Funciones anónimas como argumentos
Puedes definir funciones que reciben otras
funciones como parámetros usando el tipo
callable:
<?php
declare(strict_types=1);
// Función que acepta un callback
function aplicar(array $items, callable $transformar): array
{
$resultado = [];
foreach ($items as $item) {
$resultado[] = $transformar($item);
}
return $resultado;
}
// Función que filtra usando un callback
function filtrar(array $items, callable $condicion): array
{
$resultado = [];
foreach ($items as $item) {
if ($condicion($item)) {
$resultado[] = $item;
}
}
return $resultado;
}
$numeros = [1, 2, 3, 4, 5];
// Pasar función anónima
$dobles = aplicar($numeros, function (int $n): int {
return $n * 2;
});
print_r($dobles); // [2, 4, 6, 8, 10]
$mayoresQue2 = filtrar($numeros, function (int $n): bool {
return $n > 2;
});
print_r($mayoresQue2); // [3, 4, 5]
Retornar funciones anónimas
Las funciones pueden retornar otras funciones, creando "fábricas de funciones":
<?php
declare(strict_types=1);
// Fábrica de multiplicadores
function crearMultiplicador(int $factor): callable
{
return function (int $numero) use ($factor): int {
return $numero * $factor;
};
}
$duplicar = crearMultiplicador(2);
$triplicar = crearMultiplicador(3);
$porDiez = crearMultiplicador(10);
echo $duplicar(5); // 10
echo $triplicar(5); // 15
echo $porDiez(5); // 50
// Fábrica de validadores
function crearValidadorLongitud(int $min, int $max): callable
{
return function (string $texto) use ($min, $max): bool {
$longitud = strlen($texto);
return $longitud >= $min && $longitud <= $max;
};
}
$validarUsername = crearValidadorLongitud(3, 20);
$validarPassword = crearValidadorLongitud(8, 100);
var_dump($validarUsername('ab')); // false
var_dump($validarUsername('usuario')); // true
var_dump($validarPassword('12345')); // false
var_dump($validarPassword('password123')); // true
Funciones anónimas inmediatamente invocadas (IIFE)
Puedes definir y ejecutar una función anónima en una sola expresión:
<?php
declare(strict_types=1);
// IIFE - Immediately Invoked Function Expression
$resultado = (function (): int {
$a = 10;
$b = 20;
return $a + $b;
})();
echo $resultado; // 30
// Útil para encapsular lógica compleja
$config = (function (): array {
$env = getenv('APP_ENV') ?: 'development';
return match ($env) {
'production' => [
'debug' => false,
'cache' => true,
'log_level' => 'error',
],
'staging' => [
'debug' => true,
'cache' => true,
'log_level' => 'warning',
],
default => [
'debug' => true,
'cache' => false,
'log_level' => 'debug',
],
};
})();
print_r($config);
Ejemplo práctico: Sistema de eventos
<?php
declare(strict_types=1);
// Sistema de eventos simple usando arrays y funciones
// Almacenar listeners en un array
$listeners = [];
// Función para registrar un listener
function registrarEvento(array &$listeners, string $evento, callable $callback): void
{
if (!isset($listeners[$evento])) {
$listeners[$evento] = [];
}
$listeners[$evento][] = $callback;
}
// Función para emitir un evento
function emitirEvento(array $listeners, string $evento, array $datos = []): void
{
if (!isset($listeners[$evento])) {
return;
}
foreach ($listeners[$evento] as $callback) {
$callback($datos);
}
}
// Registrar listeners
registrarEvento($listeners, 'usuario.creado', function (array $usuario): void {
echo "Enviando email de bienvenida a {$usuario['email']}\n";
});
registrarEvento($listeners, 'usuario.creado', function (array $usuario): void {
echo "Registrando en analytics: nuevo usuario {$usuario['nombre']}\n";
});
$logPrefix = '[LOG]';
registrarEvento($listeners, 'usuario.creado', function (array $usuario) use ($logPrefix): void {
echo "$logPrefix Usuario creado: {$usuario['nombre']}\n";
});
// Emitir evento
$nuevoUsuario = ['nombre' => 'Carlos', 'email' => 'carlos@example.com'];
emitirEvento($listeners, 'usuario.creado', $nuevoUsuario);
// Salida:
// Enviando email de bienvenida a carlos@example.com
// Registrando en analytics: nuevo usuario Carlos
// [LOG] Usuario creado: Carlos
<?php
declare(strict_types=1);
// Pipeline de transformaciones usando funciones
function crearPipeline(): array
{
return ['pasos' => []];
}
function agregarPaso(array &$pipeline, callable $paso): void
{
$pipeline['pasos'][] = $paso;
}
function ejecutarPipeline(array $pipeline, mixed $input): mixed
{
$resultado = $input;
foreach ($pipeline['pasos'] as $paso) {
$resultado = $paso($resultado);
}
return $resultado;
}
// Crear pipeline de procesamiento de texto
$pipeline = crearPipeline();
agregarPaso($pipeline, function (string $texto): string {
return trim($texto);
});
agregarPaso($pipeline, function (string $texto): string {
return strtolower($texto);
});
agregarPaso($pipeline, function (string $texto): string {
return preg_replace('/\s+/', ' ', $texto) ?? $texto;
});
agregarPaso($pipeline, function (string $texto): string {
return ucfirst($texto);
});
$entrada = ' HOLA MUNDO ';
$salida = ejecutarPipeline($pipeline, $entrada);
echo $salida; // "Hola mundo"
Ejercicios
Ejercicio 1: Funcion anonima basica
Crea una funcion anonima asignada a la
variable $esMayorDeEdad que
reciba una edad (int) y retorne
true si es 18 o mas,
false en caso contrario.
Ver solucion
<?php
declare(strict_types=1);
$esMayorDeEdad = function (int $edad): bool {
return $edad >= 18;
};
var_dump($esMayorDeEdad(20)); // true
var_dump($esMayorDeEdad(15)); // false
var_dump($esMayorDeEdad(18)); // true
Ejercicio 2: Captura de variables con use
Crea una funcion anonima que calcule el
precio con IVA. La variable
$iva (0.21) debe capturarse
con use. La funcion recibe
un precio (float) y retorna el precio
con IVA aplicado.
Ver solucion
<?php
declare(strict_types=1);
$iva = 0.21;
$calcularPrecioConIva = function (float $precio) use ($iva): float {
return $precio * (1 + $iva);
};
echo $calcularPrecioConIva(100.0); // 121.0
echo $calcularPrecioConIva(50.0); // 60.5
Ejercicio 3: Funcion como callback
Usa array_filter con una
funcion anonima para filtrar un array de
numeros, quedandote solo con los que
sean divisibles por 3. Array de entrada:
[1, 3, 6, 7, 9, 12, 15, 16].
Ver solucion
<?php
declare(strict_types=1);
$numeros = [1, 3, 6, 7, 9, 12, 15, 16];
$divisiblesPor3 = array_filter($numeros, function (int $n): bool {
return $n % 3 === 0;
});
print_r(array_values($divisiblesPor3));
// [3, 6, 9, 12, 15]
¿Has encontrado un error o tienes una sugerencia para mejorar esta lección?
Escríbenos¿Te está gustando el curso?
Tenemos cursos premium con proyectos reales y soporte personalizado.
Descubrir cursos premium