# PHP para Iniciantes: Estruturas de Controle - FOREACH

No artigo anterior (desta série), falei sobre a estrutura `for`. De quebra, em outro artigo, fiz [uma implementação da estrutura de forma recursiva e semântica](https://blog.kaiquegarcia.dev/challengeaccepted-for-recursivo), mostrando o que rola por baixo das execuções.

Então agora você já sabe como escrever um laço genérico, inclusive dá pra fazer o que vamos escrever hoje com `for`.

> Ué, Kiko... Então pra que serve o `foreach`?

Para trazer uma melhor semântica para um contexto específico.

## O que faz um `foreach`?

<center> ![foreach...](https://media.giphy.com/media/26DMVBP5MLkooJV28/giphy.gif) </center>

**For Each** significa **Para Cada** em inglês. Isso evidencia que toda entrada desse tipo de estrutura precisa ser um conjunto de dados. E é isso mesmo, nós já temos um tipo de dados primitivos que identifica esse caso, [o tipo `iterable`](https://blog.kaiquegarcia.dev/php-para-iniciantes-tipos-de-dados-primitivos-iteraveis).

Com isso, nós podemos executar uma ação para cada elemento desse conjunto, não necessariamente tendo como objetivo afetar os dados desses caras.

> E como isso se assemelha a um `for`, Kiko?

Simples: todo `foreach` tem como condição **percorrer todos os elementos do conjunto**. Em um `for`, isso seria algo como:

```php
<?php

$array = [1, 2, 3, 4, 5, 6];
$quantidadeDeElementos = count($array);

for($indice = 0; $indice < $quantidadeDeElementos; $indice++) {
    $elemento = $array[$indice];
    echo $elemento . PHP_EOL;
}
```

Esse `for` percorre a lista do início ao fim, imprimindo na tela um valor por linha. Podemos reescrever isso com `foreach`:

```php
<?php

$array = [1, 2, 3, 4, 5, 6];

foreach ($array as $elemento) {
    echo $elemento . PHP_EOL;
}
```

Percebe que não precisei capturar o comprimento do `$array`, nem recuperar o `$elemento` a partir de um `$indice`?

Então a semântica dessa estrutura é: `PARA CADA ITEM DO ($array), ATRIBUA SEU VALOR À VARIÁVEL ($elemento) E FAÇA ($acao);`

E obviamente a linguagem não seguiu essa semântica à risca... Mas ainda rolou um `as` ali no meio, que serve de dica pra separar o que é iterável e o que é elemento.

> Mas Kiko, é só isso de diferença?

Não. Esse exemplo de lista (array com índices sequenciais) é o mais simples que posso mostrar, mas se criarmos um array dicionário, o primeiro código não vai funcionar.

Veja como complexo é percorrer um dicionário com `for`:

```php
<?php

$array = [
    'um' => 'Kaique',
    'dois' => 'Neris',
    'tres' => 'SwooLeo',
];

$quantidadeDeElementos = count($array);
$indices = array_keys($array); // ['um', 'dois', 'tres']

for($indiceInterno = 0; $indiceInterno < $quantidadeDeElementos; $indiceInterno++) {
    $indice = $indices[$indiceInterno];
    $elemento = $array[$indice];
    echo $elemento . PHP_EOL;
}
```

> ## QUE

<center> ![QUE](https://media.giphy.com/media/RIFv4btS2XLoI/giphy.gif) </center>

Exatamente. Em caso de dicionários, você não tem como advinhar como os índices foram escritos, logo, é preciso capturar os índices em forma de lista usando a função `array_keys` (que extrai as chaves do array).

Uma forma alternativa seria extrair os valores usando `array_values`:

```php
<?php

$array = [
    'um' => 'Kaique',
    'dois' => 'Neris',
    'tres' => 'SwooLeo',
];

$quantidadeDeElementos = count($array);
$valores = array_values($array);

for($indice = 0; $indice < $quantidadeDeElementos; $indice++) {
    $elemento = $valores[$indice];
    echo $elemento . PHP_EOL;
}
```

Mais simples? Talvez. Mas nada supera um `foreach` que funciona para ambos os casos (que é aquele que coloquei lá em cima). É bem mais legível.

> Ok, Kiko... Mas e se eu quiser acessar o índice de cada elemento?

Nesse caso, o PHP usa a sintaxe similar ao registro de um dado no array. Você sabe que há duas formas de inicializar um array com valor:

```php
// Em lista
[1, 2, 3, 4]

// Em dicionário
[
    'chave' => 'valor',
]
```

Nesse caso, o segredo está na sintaxe de dicionário. Basta inserir essa mesma sintaxe no fluxo, mas em formas de variáveis (que vão receber as informações). Por exemplo:

```php
<?php

$array = [
    'um' => 'Kaique',
    'dois' => 'Neris',
    'tres' => 'SwooLeo',
];

foreach($array as $chave => $valor) {
    echo "$chave = $valor" . PHP_EOL;
}
```

Ou seja:

- você não precisa separar as chaves dos valores (nem vice-versa);
- você não precisa capturar o comprimento do `iterable`;
- você não se limita a lidar com `array`, mas qualquer `iterable` de fato;
- você consegue compreender o laço baseado na semântica, sem depender da interpretação de condições.

<center> ![Oh yeaaah](https://media.giphy.com/media/PudZiAbQDUEik/giphy.gif) </center>

Só benefícios, né? E assim como o `for`, o `foreach` também tem a *sintaxe procedural*:

```php
<?php

foreach($array as $valor):
    // alguma coisa
endforeach;
```

## Lidando com referências

Apesar dos pesares, `foreach` tem um risco bem importante de mencionar. Se você escrever os exemplos acima, não vai rolar nada de demais nas execuções. Mas se, por ventura, você tentar modificar o valor do elemento, essa alteração não vai refletir no `array`. Isso porque os dados não são referências às posições no `iterable` e, por isso, não reflete no valor final.

**Como resolvemos isso?** Com referências:

```php
<?php

$array = [1, 2, 3, 4];

foreach($array as &$valor):
    $valor *= 2;
endforeach;

var_dump($array); // [2, 4, 6, 8]
```

Esse `foreach` está multiplicando todos os valores por `2`. Ele faz o que promete.

> Então... Onde está a pegadinha, Kiko?

No último loop. Lembra que no `for`, toda variável inicializada continua existindo fora do laço? O mesmo vale para as variáveis que recebem os valores de chaves e/ou elementos de cada iteração. O último laço irá externalizar a variável `$valor` como uma referência do último elemento do `iterable`.

**Isso é perigossíssimo**, principalmente se você tentar criar uma nova variável com a mesma nomenclatura depois. Você já sabe que o PHP não tem uma sintaxe específica para criar uma nova variável. É simplesmente definir um valor e pronto... Se a variável existia, você sobreescreve o valor, certo? **Mas o que acontece quando você define um valor para uma referência?**

```php
<?php

$array = [1, 2, 3, 4];

foreach($array as &$valor) {
    $valor *= 2;
    echo $valor . PHP_EOL;
}

var_dump($array); // [2, 4, 6, 8]
$outroArray = ['Kaique', 'Neris', 'SwooLeo'];

foreach($outroArray as $valor) {
    echo $valor . PHP_EOL;
}

var_dump($array); // [2, 4, 6, 'SwooLeo']
```

Percebeu o risco?!

> ... E tem como contornar isso, Kiko?

Felizmente **sim**. O que é necessário fazer, se você realmente precisa usar uma referência, é apagar a referência fora do loop com a função `unset`. Simples assim:

```php
<?php

$array = [1, 2, 3, 4];

foreach($array as &$valor) {
    $valor *= 2;
}

unset($valor); // retira a referência da variável $valor

var_dump($array); // [2, 4, 6, 8]
$outroArray = ['Kaique', 'Neris', 'SwooLeo'];

foreach($outroArray as $valor) {
    echo $valor . PHP_EOL;
}

var_dump($array); // [2, 4, 6, 8]
```

Esse é apenas um ponto de atenção. Se você não usar referências, você não precisa fazer isso, fechado?

E por hoje é só! Curtiu? Comenta e compartilha! No próximo artigo irei falar sobre uma estrutura super simples que serve para quebrar laços. Eu mencionei no artigo `do-while`, então vou deixar o suspense aqui. Logo, logo lanço o artigo aqui, fechado?!

**Inté!!**
