PHP Iterables
Aprenda o que são PHP Iterables, como usar arrays e objetos Traversable com foreach, e quando usar generators para sequências eficientes.
Introdução aos PHP Iterables
Em PHP, um iterable é qualquer coisa que você pode percorrer com foreach. Isso inclui dois tipos de valores:
- Arrays — a estrutura de dados do dia a dia que armazena uma coleção ordenada de pares chave/valor.
- Objetos
Traversable— objetos que o PHP sabe como percorrer, porque implementam a interface embutidaTraversable(na prática viaIteratorouIteratorAggregate, ou como um generator).
O PHP 7.1 adicionou o pseudo-tipo iterable para que você possa declarar "me dê qualquer coisa que eu possa percorrer com foreach" sem precisar saber se o chamador passa um array ou um objeto. Esta página cobre o que conta como iterable, como criar e percorrer cada tipo, e quando usar os iterables preguiçosos que os generators oferecem.
Este capítulo se baseia em PHP Arrays e no loop foreach. Se você não está familiarizado com nenhum deles, leia primeiro.
Arrays: o iterable mais comum
Arrays existem em dois formatos, e a única diferença é o tipo de chave que utilizam:
- Um array indexado armazena valores com chaves inteiras automáticas, começando em
0. Veja Arrays Indexados. - Um array associativo usa strings (ou inteiros que você escolhe) como chaves. Veja Arrays Associativos.
Um único array pode misturar ambos os estilos, e os valores podem ser de qualquer tipo de dado.
Criando e acessando arrays
Crie um array com colchetes e leia um valor pela sua chave:
PHP define and access an array
<?php
$fruits = ["apple", "banana", "cherry"]; // indexed
$student = ["name" => "John Doe", "age" => 25]; // associative
echo $fruits[0] . "\n"; // apple (first element, index 0)
echo $student["name"] . "\n"; // John DoeSaída:
apple
John DoeNote que arrays indexados são baseados em zero, portanto $fruits[0] é o primeiro elemento.
Iterando um array com foreach
foreach é a maneira idiomática de percorrer um iterable. Para um array indexado você geralmente quer apenas o valor; para um array associativo você normalmente quer tanto a chave quanto o valor:
PHP iterate over arrays
<?php
$fruits = ["apple", "banana", "cherry"];
$student = ["name" => "John Doe", "age" => 25];
foreach ($fruits as $fruit) {
echo $fruit . "\n";
}
foreach ($student as $key => $value) {
echo "$key: $value\n";
}Saída:
apple
banana
cherry
name: John Doe
age: 25Funções úteis para arrays
O PHP possui dezenas de funções para arrays. Algumas que você usará constantemente:
array_keys($arr)— retorna todas as chaves como um novo array.array_values($arr)— retorna todos os valores, re-indexados a partir de0.count($arr)— retorna o número de elementos.sort($arr)— ordena os valores em ordem crescente no próprio array, retornandotrueem caso de sucesso (não retorna o array ordenado).in_array($needle, $arr)—truese o valor existir.
PHP array functions in action
<?php
$scores = [40, 10, 30];
echo count($scores) . "\n"; // 3
print_r(array_keys($scores)); // [0, 1, 2]
sort($scores); // modifies $scores in place
print_r($scores); // [10, 30, 40]Saída:
3
Array
(
[0] => 0
[1] => 1
[2] => 2
)
Array
(
[0] => 10
[1] => 30
[2] => 40
)O pseudo-tipo iterable
iterable não é uma classe — é uma type hint que significa "array ou Traversable". Use-o em um parâmetro ou tipo de retorno quando sua função apenas precisa iterar, e você não quer forçar os chamadores a converter seus dados em um array simples primeiro.
PHP iterable type hint
<?php
function sumAll(iterable $numbers): int
{
$total = 0;
foreach ($numbers as $n) {
$total += $n;
}
return $total;
}
echo sumAll([1, 2, 3]) . "\n"; // works with an array
function countToThree(): iterable { // a generator is also iterable
yield 1;
yield 2;
yield 3;
}
echo sumAll(countToThree()) . "\n"; // works with a Traversable tooSaída:
6
6O benefício: sumAll() aceita um array regular e um fluxo gerado de forma preguiçosa sem nenhum código extra. Veja PHP Functions para mais informações sobre type hints.
Generators: iterables preguiçosos
Um generator é uma função que usa yield em vez de return. Ele produz valores um de cada vez, somente quando o loop pede o próximo, portanto nunca constrói toda a coleção na memória. Isso é ideal para sequências grandes ou infinitas.
PHP generator example
<?php
function range_lazy(int $start, int $end): iterable
{
for ($i = $start; $i <= $end; $i++) {
yield $i; // pauses here and resumes on the next iteration
}
}
foreach (range_lazy(1, 5) as $value) {
echo $value . " ";
}
echo "\n";Saída:
1 2 3 4 5Como nada é armazenado, range_lazy(1, 1_000_000) usa a mesma quantidade mínima de memória que range_lazy(1, 5).
Objetos iterables personalizados com Iterator
Quando você quer controle total sobre como um objeto é percorrido, implemente a interface Iterator. Ela requer cinco métodos que o foreach chama internamente: rewind(), valid(), current(), key() e next().
PHP custom Iterator
<?php
class EvenNumbers implements Iterator
{
private int $position = 0;
public function __construct(private array $items) {}
public function rewind(): void { $this->position = 0; }
public function valid(): bool { return isset($this->items[$this->position]); }
public function current(): mixed { return $this->items[$this->position]; }
public function key(): mixed { return $this->position; }
public function next(): void { $this->position++; }
}
$evens = new EvenNumbers([2, 4, 6]);
foreach ($evens as $n) {
echo $n . " ";
}
echo "\n";Saída:
2 4 6Na maioria das vezes um generator é mais simples do que uma classe Iterator completa — use Iterator apenas quando precisar de comportamento personalizado de rewind/key ou quando quiser expor a iteração como parte da API pública de um objeto.
Verificando se um valor é iterable
Use is_iterable() para testar em tempo de execução se um valor pode ser passado para foreach:
PHP is_iterable check
<?php
var_dump(is_iterable([1, 2, 3])); // bool(true)
var_dump(is_iterable("a string")); // bool(false)
var_dump(is_iterable((function () { yield 1; })())); // bool(true)Saída:
bool(true)
bool(false)
bool(true)Conclusão
"Iterable" em PHP significa simplesmente percorrível com foreach — e isso abrange arrays, objetos Iterator/IteratorAggregate e generators igualmente. Use arrays simples para coleções comuns, a type hint iterable para escrever funções que aceitem qualquer um deles, e generators quando a memória importa ou a sequência é grande. Com essas ferramentas você pode modelar dados de forma eficiente e manter suas APIs flexíveis.