Funciones Anónimas en PHP: Ejemplos con Callbacks y Closures
14-10-2025 | PHP function 7 min
- Asignar una función anónima a una variable
- Funciones anónimas como argumento
- Filtros
- Helper
- Manejadores de eventos
- Closure
Anónimo significa sin nombre o de nombre no conocido. Las funciones anónimas serían entonces funciones sin nombre. Su estructura básica es:
function () {
return 'Example';
};
Como no tienen nombre, no se pueden llamar directamente. Normalmente se asignan a una variable o se usan como argumentos de otras funciones. Comencemos viendo cómo asignar una función anónima a una variable.
Asignar una función anónima a una variable
$greet = function ($name) {
return "Hello, $name";
};
En este ejemplo, la variable $greet
contiene una función anónima que toma un parámetro $name
y devuelve un saludo. Veamos otras formas de definir esta estructura:
- En esencia es lo mismo pero incluimos el tipo de dato del parámetro y el tipo de dato que devuelve la función:
$greet = function (string $name): string {
return "Hello, $name";
};
- Otra forma más concisa, si la función es muy simple y consta de una sola expresión podemos usar la sintaxis de función flecha (arrow function):
$greet = fn($name) => "Hello, $name";
- Y de hecho, podemos combinar ambas cosas:
$greet = fn(string $name): string => "Hello, $name";
En cada ejemplo, como puedes ver, la variable $greet
es una función anónima y para ejecutarla, se usa la variable como si fuese una función.
echo $greet('Graaan'); // Imprime "Hello, Graaan"
Funciones anónimas como argumento
Se puede por supuesto definir una función anónima directamente como argumento de otra función. De hecho, es una práctica común en PHP, especialmente cuando se trabaja con funciones como array_map
, array_filter
y otras:
- Ejemplo con
array_map
: Multiplicamos por 2 cada número del array.
$numbers = [3, 6, 9];
$doubled = array_map(function($n) {
return $n * 2;
}, $numbers);
print_r($doubled); // Imprime [6, 12, 18]
- Ejemplo con
array_filter
: Filtramos los nombres que tienen más de 4 letras.
$names = ['Luis', 'Graaan', 'Isabella'];
$filtered = array_filter($names, function($name) {
return strlen($name) > 4;
});
print_r($filtered);
// Imprime ['Graaan', 'Isabella']
Ahora hagamos un ejemplo propio, la idea es crear una función que reciba una función anónima como argumento y la ejecute:
function test(callable $callback): string {
return $callback();
}
$result = test(function() {
return 'Función anónima como argumento';
});
echo $result; // Imprime "Función anónima como argumento"
Si bien este ejemplo demuestra la estructura, no tiene mucha utilidad práctica. Por ello te mostraré algunos ejemplos mas útiles donde veremos cómo inyectar lógica personalizada o comportamiento dinámico.
Filtros
$data = [
'username' => 'italofantone',
'is_admin' => true
];
function handle(array $data, callable $next): string {
if (!isset($data['is_admin']) || $data['is_admin'] !== true) {
return 'Access denied';
}
return $next($data);
}
$result = handle($data, function(array $data): string {
return 'Welcome ' . $data['username'];
});
echo $result; // Imprime "Welcome italofantone"
Aquí nuestro filtro handle
verifica si el usuario es administrador. Si no lo es, devuelve "Access denied". Si lo es, ejecuta la función anónima pasada como argumento, que genera un mensaje de bienvenida personalizado. Simplemente cambiando la función anónima podemos modificar el comportamiento sin cambiar la función handle
.
Podría decirse que handle
es una lógica central que aplica un filtro de seguridad, y la función anónima es la lógica específica que se ejecuta si el filtro pasa.
Helper
A veces necesitamos una función que realice una tarea específica, me refiero a encapsular a determinada lógica repetitiva. En estos casos, las funciones anónimas son útiles como helpers:
function executionTime(callable $callback): float {
$start = microtime(true);
$callback();
return microtime(true) - $start;
}
$duration = executionTime(function() {
sleep(3);
return 'Function executed';
});
echo "$duration seconds"; // Imprime "3.0050208568573 seconds"
Con esto logramos medir el tiempo que tarda en ejecutarse cualquier función que le pasemos como argumento. En este caso, la función anónima demora 3 segundos (para el ejemplo usé sleep(3)
), pero podría ser cualquier otra cosa que querramos medir.
Manejadores de eventos
En este ejemplo aprenderás un concepto que, aunque puede parecer sencillo, se convierte en una base sólida para cuando trabajes con frameworks más avanzados como Laravel.
Imagina un sistema sencillo capaz de registrar y disparar eventos. Entendiendo que un evento es una acción que ocurre en el sistema, y un listener es una función que responde a ese evento.
user.registered
: Cuando un usuario se registra.user.updated
: Cuando un usuario actualiza su información.user.deleted
: Cuando un usuario es eliminado.
Estos son mis eventos, y cada uno de ellos puede tener múltiples listeners asociados que se van a ejecutar cuando el evento ocurre.
Veamos entonces nuestra clase Event
, que se encargará de registrar los diferentes listeners y dispararlos cuando un evento ocurra:
class Event
{
protected $listeners = [];
public function listen(string $event, callable $callback): void
{
$this->listeners[$event][] = $callback;
}
public function dispatch(string $event, mixed $payload = null): void
{
foreach ($this->listeners[$event] ?? [] as $listener) {
$listener($payload);
}
}
}
Ahora podemos registrar listeners para nuestros eventos usando funciones anónimas:
$event = new Event();
$event->listen('user.registered', function (string $username) {
echo "User registered: " . $username . PHP_EOL;
});
$event->listen('user.registered', function (string $username) {
echo "Send welcome email to: " . $username . PHP_EOL;
});
$event->listen('user.updated', function (array $data) {
echo "User updated: " . json_encode($data) . PHP_EOL;
});
La lógica dice que cuando un usuario se registre, se ejecutarán dos listeners: uno que imprime un mensaje y otro que simula el envío de un correo de bienvenida. Si un usuario actualiza su información, se ejecutará otro listener que imprime los datos actualizados.
Pero hay algo interesante, estamos trabajando con un string y un array, pero podríamos pasar cualquier tipo de dato como payload, incluso objetos. Veamos cómo funciona todo esto en acción:
$event->listen('user.deleted', function (User $user) {
echo "User deleted: " . $user->username . PHP_EOL;
});
class User
{
public function __construct(
public string $username,
) {}
}
$event->dispatch('user.deleted', new User('italofantone'));
En este caso registramos un listener para el evento user.deleted
que recibe un objeto User
. Cuando despachamos el evento, pasamos una instancia de User
, y el listener puede acceder a sus propiedades.
Esto es así de flexible gracias al $payload
que puede ser cualquier tipo de dato, y los listeners pueden manejarlo según sus necesidades. Esto podría traducirse a carga valiosa que contiene lo que realmente se necesita, es en realidad un nombre genérico que nos brinda flexibilidad, escalabilidad, desacoplamiento y reutilización de código.
Para que esto se entienda bien, debes tener la imagen del array en mente:
$listeners = [
'user.registered' => [
0 => Closure // Primera función anónima
1 => Closure // Segunda función anónima
],
'user.updated' => [
0 => Closure // Función anónima única
],
'user.deleted' => [
0 => Closure // Función anónima única
]
]
Closure
Un closure es una función anónima que puede capturar variables externas, es decir, fuera de la función. En esencia, es una función anónima con algo de contexto.
$username = 'italofantone';
$greet = function() use ($username) {
return "Hello, $username";
};
echo $greet(); // Imprime "Hello, italofantone"
Nota que la clave aquí es la palabra reservada use
, que permite a la función anónima capturar la variable $username
del scope externo. Sin use
, la función no tendría acceso a $username
.
Veamos algunos conceptos clave:
- Función anónima: Es directamente una función sin nombre.
- Closure: Es una función anónima que puede capturar variables externas usando
use
. - Callback: Es un término más general que se refiere a cualquier función (anónima o nombrada) que se pasa como argumento a otra función.