Arrow Functions

1. Introdução às Arrow Functions

Arrow functions representam uma das adições mais elegantes ao PHP moderno. Introduzidas no PHP 7.4, elas oferecem uma sintaxe concisa para escrever funções anônimas de uma única expressão. A estrutura básica é fn($x) => $x * 2, que substitui closures tradicionais mais verbosas.

Antes das arrow functions, um closure simples para dobrar um número exigia:

$dobrar = function($x) {
    return $x * 2;
};

Com arrow functions, o mesmo código se reduz a:

$dobrar = fn($x) => $x * 2;

A diferença visual é marcante: menos cerimônia, mais foco na lógica essencial.

2. Sintaxe Básica

A estrutura mínima de uma arrow function segue o padrão fn(argumentos) => expressão. O retorno é implícito — não há necessidade de return.

// Sintaxe básica
$quadrado = fn($n) => $n * $n;
echo $quadrado(5); // 25

// Múltiplos parâmetros
$soma = fn($a, $b) => $a + $b;
echo $soma(3, 7); // 10

Parâmetros tipados e valores padrão funcionam normalmente:

// Com type hinting
$calcular = fn(int $a, int $b): int => $a + $b;

// Valores padrão
$saudacao = fn(string $nome = 'Mundo') => "Olá, $nome!";
echo $saudacao(); // Olá, Mundo!
echo $saudacao('Maria'); // Olá, Maria!

3. Captura de Variáveis do Escopo Pai

Uma das vantagens mais significativas das arrow functions é a captura automática de variáveis do escopo pai. Diferente das closures tradicionais, que exigem use explícito, as arrow functions capturam variáveis automaticamente por valor.

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

// Closure tradicional — requer 'use'
$multiplicarTradicional = array_map(function($n) use ($fator) {
    return $n * $fator;
}, $numeros);

// Arrow function — captura automática
$multiplicarArrow = array_map(fn($n) => $n * $fator, $numeros);

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

A captura inclui $this automaticamente em contextos de objeto:

class Conversor {
    private float $taxa = 1.25;

    public function converter(array $valores): array {
        // $this está disponível automaticamente
        return array_map(fn($v) => $v * $this->taxa, $valores);
    }
}

$conv = new Conversor();
print_r($conv->converter([100, 200])); // [125, 250]

4. Limitações Importantes

Arrow functions têm restrições claras que é essencial conhecer:

Apenas uma expressão: não é possível usar chaves {} ou múltiplas instruções.

// Inválido — não compile
$invalido = fn($x) => {
    $y = $x * 2;
    return $y + 1;
};

// Correto — deve ser expressão única
$valido = fn($x) => ($x * 2) + 1;

Sem suporte a declarações: estruturas como if, for, while não são permitidas.

// Inválido
$parOuImpar = fn($n) => if ($n % 2 === 0) 'par' else 'impar';

// Alternativa com operador ternário
$parOuImpar = fn($n) => ($n % 2 === 0) ? 'par' : 'impar';

Sem referências explícitas: não é possível usar & para capturar por referência.

$contador = 0;

// Não funciona como esperado — arrow function captura por valor
$incrementar = fn() => $contador++;
$incrementar(); // $contador continua 0

// Closure tradicional com referência
$incrementarRef = function() use (&$contador) {
    $contador++;
};
$incrementarRef(); // $contador agora é 1

5. Uso com Funções de Array

Arrow functions brilham especialmente com funções de manipulação de arrays, reduzindo drasticamente a verbosidade do código.

array_map — transformação concisa:

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

// Closure tradicional
$aoQuadradoTrad = array_map(function($n) {
    return $n ** 2;
}, $numeros);

// Arrow function
$aoQuadradoArrow = array_map(fn($n) => $n ** 2, $numeros);

print_r($aoQuadradoArrow); // [1, 4, 9, 16, 25]

array_filter — filtragem simplificada:

$idades = [12, 18, 25, 30, 15, 22];

// Filtrar maiores de idade com variável externa
$idadeMinima = 18;
$maiores = array_filter($idades, fn($idade) => $idade >= $idadeMinima);

print_r($maiores); // [18, 25, 30, 22]

array_reduce — redução elegante:

$valores = [10, 20, 30, 40];

// Soma com arrow function
$soma = array_reduce($valores, fn($carry, $item) => $carry + $item, 0);
echo $soma; // 100

6. Arrow Functions Aninhadas e Callbacks

Arrow functions podem ser aninhadas e usadas como callbacks em contextos mais complexos:

// Arrow function que retorna outra arrow function
$multiplicador = fn($fator) => fn($valor) => $valor * $fator;

$dobro = $multiplicador(2);
$triplo = $multiplicador(3);

echo $dobro(5); // 10
echo $triplo(5); // 15

Uso em pipelines de processamento:

$processar = fn($arr) => 
    array_map(fn($n) => $n * 2, 
        array_filter($arr, fn($n) => $n > 0)
    );

$dados = [-1, 2, -3, 4, 5];
print_r($processar($dados)); // [4, 8, 10]

Armadilha comum de escopo aninhado:

$valores = [1, 2, 3];

// Cuidado: cada arrow function captura seu próprio escopo
$resultados = array_map(
    fn($x) => array_map(
        fn($y) => $x * $y,  // $x vem do escopo externo
        [10, 20]
    ),
    $valores
);

print_r($resultados); // [[10, 20], [20, 40], [30, 60]]

7. Performance e Boas Práticas

Arrow functions oferecem vantagens de performance por terem menos overhead que closures tradicionais — não há necessidade de criar um escopo de variáveis separado com use.

Quando usar arrow functions:
- Operações simples de transformação em arrays
- Callbacks curtos em funções como array_map, array_filter
- Expressões matemáticas ou lógicas diretas
- Contextos onde a captura automática de variáveis é desejada

Quando preferir closures tradicionais:
- Lógica com múltiplas instruções ou estruturas de controle
- Necessidade de capturar variáveis por referência
- Operações que exigem modificação de estado externo
- Código que precisa de documentação inline mais detalhada

Exemplo de boa prática:

// Bom uso de arrow function
$precosComTaxa = array_map(
    fn($preco) => $preco * (1 + $taxa),
    $precos
);

// Caso que justifica closure tradicional
$processarPedido = function($pedido) use (&$estoque, $taxa) {
    if ($estoque[$pedido['item']] < $pedido['quantidade']) {
        throw new \Exception('Estoque insuficiente');
    }
    $estoque[$pedido['item']] -= $pedido['quantidade'];
    return $pedido['preco'] * $pedido['quantidade'] * (1 + $taxa);
};

8. Casos Avançados e Curiosidades

Tipos de retorno declarados:

// Declaração explícita de tipo de retorno
$calcular = fn(int $a, int $b): int => $a + $b;

Uso com match expressions (PHP 8.0+):

$classificar = fn($nota) => match(true) {
    $nota >= 9 => 'Excelente',
    $nota >= 7 => 'Bom',
    $nota >= 5 => 'Regular',
    default => 'Insuficiente'
};

echo $classificar(8.5); // Bom

Arrow functions em métodos e traits:

trait OperacoesMatematicas {
    public function aplicarOperacao(array $valores): array {
        return array_map(fn($v) => $this->operacao($v), $valores);
    }

    abstract protected function operacao($valor);
}

class Calculadora {
    use OperacoesMatematicas;

    protected function operacao($valor) {
        return $valor ** 2;
    }
}

$calc = new Calculadora();
print_r($calc->aplicarOperacao([1, 2, 3])); // [1, 4, 9]

Arrow functions com variáveis de instância:

class Filtro {
    private int $limite = 10;

    public function filtrar(array $dados): array {
        // Captura automática de $this
        return array_filter($dados, fn($item) => $item > $this->limite);
    }
}

Arrow functions representam um avanço significativo na expressividade do PHP, permitindo código mais limpo e funcional. Dominá-las é essencial para qualquer desenvolvedor PHP moderno que busca escrever código elegante e eficiente.

Referências