Leccion 25 de 75 10 min de lectura

Arrow Functions

Las arrow functions (funciones flecha), introducidas en PHP 7.4, son una sintaxis mas concisa para escribir funciones anonimas de una sola expresion. Capturan automaticamente las variables del ambito exterior sin necesidad de usar use.

Sintaxis basica

Las arrow functions usan la palabra clave fn seguida de los parametros, una flecha => y una expresion:

PHP
<?php

declare(strict_types=1);

// Funcion anonima tradicional
$sumarTradicional = function (int $a, int $b): int {
    return $a + $b;
};

// Arrow function equivalente
$sumar = fn (int $a, int $b): int => $a + $b;

echo $sumar(5, 3); // 8

// Mas ejemplos
$duplicar = fn (int $n): int => $n * 2;
$esPar = fn (int $n): bool => $n % 2 === 0;
$saludar = fn (string $nombre): string => "Hola, $nombre";

echo $duplicar(7);      // 14
var_dump($esPar(4));    // true
echo $saludar('Maria'); // Hola, Maria
Solo una expresion

Las arrow functions solo pueden contener una expresion. No puedes usar multiples sentencias ni bloques de codigo. El resultado de la expresion se retorna automaticamente.

Captura automatica de variables

A diferencia de las funciones anonimas tradicionales, las arrow functions capturan automaticamente las variables del ambito exterior por valor:

PHP
<?php

declare(strict_types=1);

$multiplicador = 10;

// Funcion anonima: necesita use
$multiplicarTradicional = function (int $n) use ($multiplicador): int {
    return $n * $multiplicador;
};

// Arrow function: captura automatica
$multiplicar = fn (int $n): int => $n * $multiplicador;

echo $multiplicar(5); // 50

// Captura de multiples variables
$base = 100;
$descuento = 0.15;

$calcularPrecio = fn (float $precio): float => $base + $precio - ($precio * $descuento);

echo $calcularPrecio(50); // 142.5 (100 + 50 - 7.5)

Comparacion con funciones anonimas

Las arrow functions son ideales para transformaciones simples donde la sintaxis tradicional seria verbosa:

PHP
<?php

declare(strict_types=1);

$numeros = [1, 2, 3, 4, 5];
$factor = 3;

// Funcion anonima tradicional (verbosa)
$cubosTradicional = array_map(function (int $n): int {
    return $n ** 3;
}, $numeros);

// Arrow function (concisa)
$cubos = array_map(fn (int $n): int => $n ** 3, $numeros);

print_r($cubos); // [1, 8, 27, 64, 125]

// Con captura de variable
// Tradicional
$multiplicadosTradicional = array_map(function (int $n) use ($factor): int {
    return $n * $factor;
}, $numeros);

// Arrow function
$multiplicados = array_map(fn (int $n): int => $n * $factor, $numeros);

print_r($multiplicados); // [3, 6, 9, 12, 15]

Uso con funciones de arrays

Las arrow functions brillan especialmente con funciones como array_map, array_filter y usort:

PHP
<?php

declare(strict_types=1);

$productos = [
    ['nombre' => 'Laptop', 'precio' => 999.99],
    ['nombre' => 'Mouse', 'precio' => 29.99],
    ['nombre' => 'Teclado', 'precio' => 79.99],
    ['nombre' => 'Monitor', 'precio' => 349.99],
];

// Extraer solo los nombres
$nombres = array_map(fn (array $p): string => $p['nombre'], $productos);
print_r($nombres); // ['Laptop', 'Mouse', 'Teclado', 'Monitor']

// Extraer solo los precios
$precios = array_map(fn (array $p): float => $p['precio'], $productos);
print_r($precios); // [999.99, 29.99, 79.99, 349.99]

// Filtrar productos caros (mas de 100)
$caros = array_filter($productos, fn (array $p): bool => $p['precio'] > 100);
print_r($caros);
// [['nombre' => 'Laptop', ...], ['nombre' => 'Monitor', ...]]

// Aplicar descuento del 10%
$descuento = 0.10;
$conDescuento = array_map(
    fn (array $p): array => [
        'nombre' => $p['nombre'],
        'precio' => $p['precio'] * (1 - $descuento),
    ],
    $productos
);
print_r($conDescuento);

Ordenamiento con arrow functions

PHP
<?php

declare(strict_types=1);

$usuarios = [
    ['nombre' => 'Ana', 'edad' => 28],
    ['nombre' => 'Luis', 'edad' => 35],
    ['nombre' => 'Eva', 'edad' => 22],
    ['nombre' => 'Carlos', 'edad' => 30],
];

// Ordenar por edad (ascendente)
usort($usuarios, fn (array $a, array $b): int => $a['edad'] <=> $b['edad']);
// Eva(22), Ana(28), Carlos(30), Luis(35)

// Ordenar por edad (descendente)
usort($usuarios, fn (array $a, array $b): int => $b['edad'] <=> $a['edad']);
// Luis(35), Carlos(30), Ana(28), Eva(22)

// Ordenar por nombre
usort($usuarios, fn (array $a, array $b): int => $a['nombre'] <=> $b['nombre']);
// Ana, Carlos, Eva, Luis

$palabras = ['banana', 'Manzana', 'cereza', 'Uva'];

// Ordenar sin distinguir mayusculas/minusculas
usort($palabras, fn (string $a, string $b): int => strcasecmp($a, $b));
print_r($palabras); // ['banana', 'cereza', 'Manzana', 'Uva']

Encadenamiento de operaciones

Las arrow functions permiten crear cadenas de transformaciones legibles:

PHP
<?php

declare(strict_types=1);

$numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Obtener la suma de los cuadrados de los numeros pares
$resultado = array_sum(
    array_map(
        fn (int $n): int => $n ** 2,
        array_filter($numeros, fn (int $n): bool => $n % 2 === 0)
    )
);

echo $resultado; // 220 (4 + 16 + 36 + 64 + 100)

// Procesar pedidos
$pedidos = [
    ['producto' => 'A', 'cantidad' => 3, 'precio' => 10.00],
    ['producto' => 'B', 'cantidad' => 1, 'precio' => 25.00],
    ['producto' => 'C', 'cantidad' => 5, 'precio' => 5.00],
    ['producto' => 'D', 'cantidad' => 2, 'precio' => 15.00],
];

$impuesto = 0.21;

// Calcular totales con impuesto para pedidos mayores a 20
$totalesConImpuesto = array_map(
    fn (array $p): float => $p['cantidad'] * $p['precio'] * (1 + $impuesto),
    array_filter(
        $pedidos,
        fn (array $p): bool => $p['cantidad'] * $p['precio'] > 20
    )
);

print_r($totalesConImpuesto);
// [36.30 (producto A), 30.25 (producto B), 30.25 (producto C), 36.30 (producto D)]

Arrow functions anidadas

Puedes retornar arrow functions desde otras arrow functions:

PHP
<?php

declare(strict_types=1);

// Fabrica de multiplicadores
$crearMultiplicador = fn (int $factor): callable => fn (int $n): int => $n * $factor;

$duplicar = $crearMultiplicador(2);
$triplicar = $crearMultiplicador(3);
$porCien = $crearMultiplicador(100);

echo $duplicar(5);  // 10
echo $triplicar(5); // 15
echo $porCien(5);   // 500

// Fabrica de comparadores
$crearComparador = fn (string $campo): callable =>
    fn (array $a, array $b): int => $a[$campo] <=> $b[$campo];

$usuarios = [
    ['nombre' => 'Ana', 'puntos' => 150],
    ['nombre' => 'Luis', 'puntos' => 200],
    ['nombre' => 'Eva', 'puntos' => 100],
];

// Ordenar por puntos
usort($usuarios, $crearComparador('puntos'));
print_r($usuarios);
// Eva(100), Ana(150), Luis(200)

// Ordenar por nombre
usort($usuarios, $crearComparador('nombre'));
print_r($usuarios);
// Ana, Eva, Luis

Limitaciones de las arrow functions

Es importante conocer cuando no usar arrow functions:

PHP
<?php

declare(strict_types=1);

// NO PUEDES: usar multiples lineas
// fn (int $n): int => {
//     $resultado = $n * 2;
//     return $resultado;
// };

// SI PUEDES: usar funcion anonima para logica compleja
$procesarComplejo = function (array $datos): array {
    $resultado = [];
    foreach ($datos as $item) {
        if ($item > 0) {
            $resultado[] = $item * 2;
        }
    }
    return $resultado;
};

// NO PUEDES: capturar por referencia
$contador = 0;
// fn (): int => ++$contador; // No modifica el original

// SI PUEDES: usar funcion anonima con &
$incrementar = function () use (&$contador): int {
    return ++$contador;
};

echo $incrementar(); // 1
echo $incrementar(); // 2
echo $contador;      // 2

// NO PUEDES: usar sentencias (solo expresiones)
// fn (): void => echo 'hola'; // Error: echo es una sentencia

// SI PUEDES: retornar el resultado de una expresion
$obtenerMensaje = fn (): string => 'hola';
Cuando usar cada una

Usa arrow functions para transformaciones simples de una linea. Usa funciones anonimas tradicionales cuando necesites multiples sentencias, captura por referencia, o logica compleja.

Ejemplo practico: Validador de datos

PHP
<?php

declare(strict_types=1);

// Definir validadores como arrow functions
$esRequerido = fn (mixed $valor): bool => $valor !== null && $valor !== '';
$esEmail = fn (string $valor): bool => filter_var($valor, FILTER_VALIDATE_EMAIL) !== false;
$longitudMinima = fn (int $min): callable => fn (string $valor): bool => strlen($valor) >= $min;
$longitudMaxima = fn (int $max): callable => fn (string $valor): bool => strlen($valor) <= $max;
$esNumerico = fn (mixed $valor): bool => is_numeric($valor);
$entreValores = fn (int $min, int $max): callable =>
    fn (int $valor): bool => $valor >= $min && $valor <= $max;

// Funcion para validar un campo con multiples reglas
function validarCampo(mixed $valor, array $reglas): array
{
    $errores = [];

    foreach ($reglas as $nombre => $regla) {
        if (!$regla($valor)) {
            $errores[] = $nombre;
        }
    }

    return $errores;
}

// Validar un email
$email = 'usuario@example.com';
$erroresEmail = validarCampo($email, [
    'requerido' => $esRequerido,
    'formato_email' => $esEmail,
    'longitud_minima' => $longitudMinima(5),
    'longitud_maxima' => $longitudMaxima(100),
]);

if (empty($erroresEmail)) {
    echo "Email valido\n";
} else {
    echo 'Errores: ' . implode(', ', $erroresEmail) . "\n";
}

// Validar edad
$edad = 25;
$erroresEdad = validarCampo($edad, [
    'requerido' => $esRequerido,
    'numerico' => $esNumerico,
    'rango_valido' => $entreValores(18, 120),
]);

var_dump(empty($erroresEdad)); // true

Ejemplo practico: Transformacion de datos

PHP
<?php

declare(strict_types=1);

// Datos de usuarios de una API
$usuariosApi = [
    ['id' => 1, 'first_name' => 'ana', 'last_name' => 'garcia', 'active' => 1],
    ['id' => 2, 'first_name' => 'luis', 'last_name' => 'perez', 'active' => 0],
    ['id' => 3, 'first_name' => 'eva', 'last_name' => 'lopez', 'active' => 1],
];

// Transformadores
$capitalizar = fn (string $texto): string => ucfirst(strtolower($texto));
$nombreCompleto = fn (array $u): string => $capitalizar($u['first_name']) . ' ' . $capitalizar($u['last_name']);
$esActivo = fn (array $u): bool => $u['active'] === 1;

// Transformar datos
$usuariosActivos = array_filter($usuariosApi, $esActivo);
$nombres = array_map($nombreCompleto, $usuariosActivos);

print_r($nombres); // ['Ana Garcia', 'Eva Lopez']

// Crear estructura para la vista
$usuariosVista = array_map(
    fn (array $u): array => [
        'id' => $u['id'],
        'nombre' => $nombreCompleto($u),
        'estado' => $esActivo($u) ? 'Activo' : 'Inactivo',
    ],
    $usuariosApi
);

print_r($usuariosVista);
/*
[
    ['id' => 1, 'nombre' => 'Ana Garcia', 'estado' => 'Activo'],
    ['id' => 2, 'nombre' => 'Luis Perez', 'estado' => 'Inactivo'],
    ['id' => 3, 'nombre' => 'Eva Lopez', 'estado' => 'Activo'],
]
*/

Ejercicios

Ejercicio 1: Arrow function basica

Convierte esta funcion anonima a arrow function: $cuadrado = function (int $n): int { return $n * $n; };

Ver solucion
PHP
<?php
declare(strict_types=1);

$cuadrado = fn (int $n): int => $n * $n;

echo $cuadrado(5);  // 25
echo $cuadrado(12); // 144

Ejercicio 2: Captura automatica de variables

Tienes una variable $descuento = 0.15. Crea una arrow function $aplicarDescuento que reciba un precio y retorne el precio con el descuento aplicado. Recuerda que las arrow functions capturan variables automaticamente.

Ver solucion
PHP
<?php
declare(strict_types=1);

$descuento = 0.15;

$aplicarDescuento = fn (float $precio): float => $precio * (1 - $descuento);

echo $aplicarDescuento(100.0); // 85.0
echo $aplicarDescuento(50.0);  // 42.5

Ejercicio 3: Transformar array con arrow function

Usa array_map con una arrow function para convertir un array de temperaturas en Celsius a Fahrenheit. Formula: F = C * 9/5 + 32. Array de entrada: [0, 20, 100].

Ver solucion
PHP
<?php
declare(strict_types=1);

$celsius = [0, 20, 100];

$fahrenheit = array_map(
    fn (int $c): float => $c * 9 / 5 + 32,
    $celsius
);

print_r($fahrenheit);
// [32.0, 68.0, 212.0]

¿Te está gustando el curso?

Tenemos cursos premium con proyectos reales y soporte personalizado.

Descubrir cursos premium