Como usar map, filter e reduce no PHP
Tags: php, functional
Published: 2020-05-13 04:55:43

No artigo anterior, eu falei sobre o uso de _arrow functions_ dentro do PHP. Você pode lê-lo [neste link](https://dev.to/lucascavalcante/facilitando-o-entendimento-da-arrow-function-no-php-9a2).

Hoje, seguindo com a aplicação de conceitos funcionais no PHP, vamos falar sobre 3 funções amplamente utlizadas quando precisamos percorrer um array e, se fossemos usar um loop tradicional, teríamos um pouco mais de trabalho. Estou falando do `array_map`, `array_filter` e o `array_reduce`.

Para começar, vamos usar um array que será aplicado em todos os exemplos deste artigo. Um array com os **Top 3** filmes que mais arrecadaram na história do cinema. Vamos ter o título do filme, nota no IMDB, faturamento nos Estados Unidos, e faturamento no Brasil.

```php
    $filmes = [
        [
            'titulo' => 'Vingadores: Ultimato',
            'imdb' => 8.4,
            'faturamento_us' => 858300000,
            'faturamento_br' => 85660000
        ],
        [
            'titulo' => 'Avatar',
            'imdb' => 7.8,
            'faturamento_us' => 760500000,
            'faturamento_br' => 58210000
        ],
        [
            'titulo' => 'Titanic',
            'imdb' => 7.8,
            'faturamento_us' => 659360000,
            'faturamento_br' => 70460000
        ],
    ];
```

### array_map

A função `array_map` tem como objetivo percorrer todo o array e **mapear** cada um dos itens processando-os com o que é pedido, e gerando um novo array com os novos valores.

No nosso exemplo, vamos supor que o valor total das arrecadações são valores brutos, e que nós vamos descontar os impostos para mostrar o valor líquido. Vamos usar os valores fictícios de 16% para o Brasil e 6% para os Estados Unidos.

```php
    $filmesDepoisDosImpostos = array_map(function ($filme) {
        $filme['faturamento_us'] -= $filme['faturamento_us'] * 0.06;
        $filme['faturamento_br'] -= $filme['faturamento_br'] * 0.16;
        return $filme;
    }, $filmes);

    var_dump($filmesDepoisDosImpostos);
```
Você pode perceber que a função `array_map` recebe 2 parâmetros: o primeiro é a função onde o mapeamento é feito, e o segundo é o array que irá fornecer os dados para serem mapeados.

### array_filter

A função `array_filter` tem como objetivo **filtrar** os itens do array que atendam a uma condição estipulada dentro da função, e gerando um novo array apenas com os itens filtrados.

Por exemplo, eu quero filtrar pelos filmes que tenham a nota no IMDB abaixo de 8.

```php
    $filmesNotaMenorQueOito = array_filter($filmes, function ($filme) {
        return $filme['imdb'] < 8;
    });

    var_dump($filmesNotaMenorQueOito);
```
Nesse caso aqui, os parâmetros se invertem em relação ao `array_map`. O primeiro parâmetro é o array que servirá como base para a filtragem, e o segundo é a função que irá estipular a condição para o filtro.

Se você reparar na saída do código, o novo array manteve a chave original dos itens do array original. Isso pode facilitar se você quiser chamar o array original usando as mesmas chaves.

### array_reduce

A função `array_reduce` tem como objetivo **reduzir** o array a um único valor utilizando alguma operação aritmética para tal.

Neste exemplo, eu quero somar o faturamento no Brasil dos 3 filmes.

```php
    $totalFaturamentoBR = array_reduce($filmes, function ($total, $filme) {
        $total += $filme['faturamento_br'];
        return $total;
    }, 0);

    var_dump($totalFaturamentoBR);
```
Aqui, temos 3 parâmetros. O primeiro é o array original que servirá como base para a operação aritmética, o segundo é a função que irá processar o cálculo, e o terceiro (opcional) servirá como valor inicial da operação. No nosso caso, como ele está 0(zero) não faria diferença se nós o removessemos. Mas vamos supor que além desse faturamento, fossemos adicionar o valor arrecadado desses mesmos filmes com streaming. Colocariamos esse valor no terceiro parâmetro.

Achou fácil? Espero que eu tenha ajudado a elucidar suas dúvidas.

---

Para finalizar, gostaria de refazer 2 dos exemplos acima utilizando maneiras de deixar o código mais legível e clean.

### Função externa

O primeiro exemplo será com o `array_map` e será usando uma função que foi declarada fora do seu escopo.

```php
    function aplicarImposto($filme) {
        $filme['faturamento_us'] -= $filme['faturamento_us'] * 0.06;
        $filme['faturamento_br'] -= $filme['faturamento_br'] * 0.16;
        return $filme;
    }

    $filmesDepoisDosImpostos = array_map("aplicarImposto", $filmes);

    var_dump($filmesDepoisDosImpostos);
```
Criamos a função `aplicarImposto` com o mesmo formato e conteúdo da versão anterior. Dentro do `array_map`, chamamos a função como uma string, e o parâmetro é passado de forma implícita. Visualmente, fica mais fácil de entender o código, mas tudo é questão de costume.

### Arrow function

No artigo anterior falei sobre _arrow function_. A boa notícia é que podemos usá-la em conjunto com essas funções (quando o contexto permite, é claro). Lembrando que _arrow function_ só irá funcionar a partir da versão 7.4 da linguagem.

```php
    $filmesNotaMenorQueOito = array_filter($filmes, fn($filme) => $filme['imdb'] < 8);

    var_dump($filmesNotaMenorQueOito);
```
Conseguimos reduzir a 1 linha o exemplo anterior do `array_filter`.

---

E aí, o que achou? Espero que tenha gostado.

É sempre bom lembrar, dúvidas e feedbacks são sempre muito bem vindos.