PHP Iterables
Gli iterabili PHP includono array e oggetti Traversable che si possono scorrere con foreach. Scopri come crearli, usarli e quando scegliere i generatori.
Introduzione agli iterabili PHP
In PHP, un iterable è qualsiasi cosa su cui si può eseguire un ciclo con foreach. Comprende due tipi di valori:
- Array — la struttura dati comune che contiene una raccolta ordinata di coppie chiave/valore.
- Oggetti
Traversable— oggetti che PHP sa come percorrere, perché implementano l'interfaccia built-inTraversable(in pratica tramiteIteratoroIteratorAggregate, oppure come generatore).
PHP 7.1 ha introdotto lo pseudo-tipo iterable per poter dichiarare "dammi qualsiasi cosa su cui posso fare foreach" senza preoccuparsi se chi chiama passa un array o un oggetto. Questa pagina spiega cosa si considera iterable, come creare e attraversare ogni tipo, e quando usare gli iterable lazy che i generatori offrono.
Questo capitolo si basa su PHP Arrays e il ciclo foreach. Se non hai familiarità con uno dei due, leggi prima quelli.
Array: l'iterable più comune
Gli array esistono in due varianti, e l'unica differenza è il tipo di chiave utilizzato:
- Un array indicizzato memorizza i valori sotto chiavi intere automatiche, a partire da
0. Vedi Indexed Arrays. - Un array associativo utilizza stringhe (o interi a scelta) come chiavi. Vedi Associative Arrays.
Un singolo array può mescolare entrambi gli stili, e i valori possono essere di qualsiasi tipo di dato.
Creare e accedere agli array
Crea un array con parentesi quadre, poi leggi un valore tramite la sua chiave:
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 DoeOutput:
apple
John DoeSi noti che gli array indicizzati sono a base zero, quindi $fruits[0] è il primo elemento.
Iterare un array con foreach
foreach è il modo idiomatico per scorrere un iterable. Per un array indicizzato di solito si vuole solo il valore; per un array associativo si vogliono tipicamente sia la chiave che il valore:
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";
}Output:
apple
banana
cherry
name: John Doe
age: 25Funzioni utili per gli array
PHP include decine di funzioni per array. Alcune che userai continuamente:
array_keys($arr)— restituisce tutte le chiavi come nuovo array.array_values($arr)— restituisce tutti i valori, re-indicizzati da0.count($arr)— restituisce il numero di elementi.sort($arr)— ordina i valori in modo crescente in place, restituiscetruein caso di successo (non restituisce l'array ordinato).in_array($needle, $arr)—truese il valore esiste.
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]Output:
3
Array
(
[0] => 0
[1] => 1
[2] => 2
)
Array
(
[0] => 10
[1] => 30
[2] => 40
)Lo pseudo-tipo iterable
iterable non è una classe — è un type hint che significa "array o Traversable". Usalo su un parametro o tipo di ritorno quando la tua funzione deve solo fare un ciclo, e non vuoi costringere chi chiama a convertire i propri dati in un semplice array.
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 tooOutput:
6
6Il vantaggio: sumAll() accetta sia un array normale che uno stream generato pigro senza codice aggiuntivo. Vedi PHP Functions per ulteriori informazioni sui type hint.
Generatori: iterable lazy
Un generatore è una funzione che usa yield invece di return. Produce i valori uno alla volta, solo quando il ciclo chiede il successivo, quindi non costruisce mai l'intera raccolta in memoria. Questo è ideale per sequenze grandi o infinite.
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";Output:
1 2 3 4 5Poiché nulla viene memorizzato, range_lazy(1, 1_000_000) usa la stessa piccola quantità di memoria di range_lazy(1, 5).
Oggetti iterabili personalizzati con Iterator
Quando vuoi il controllo completo su come viene percorso un oggetto, implementa l'interfaccia Iterator. Richiede cinque metodi che foreach chiama 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";Output:
2 4 6Nella maggior parte dei casi un generatore è più semplice di una classe Iterator completa — ricorri a Iterator solo quando hai bisogno di un comportamento personalizzato di rewind/key o vuoi esporre l'iterazione come parte dell'API pubblica di un oggetto.
Verificare se un valore è iterable
Usa is_iterable() per verificare in fase di esecuzione se un valore può essere passato a 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)Output:
bool(true)
bool(false)
bool(true)Conclusione
"Iterable" in PHP significa semplicemente iterabile con foreach — e questo comprende array, oggetti Iterator/IteratorAggregate e generatori allo stesso modo. Usa i normali array per le raccolte ordinarie, il type hint iterable per scrivere funzioni che accettano qualsiasi di essi, e i generatori quando la memoria è importante o la sequenza è grande. Con questi strumenti puoi modellare i dati in modo efficiente e mantenere le tue API flessibili.