W3docs

PHP Iterables

PHP Iterables sind Datenstrukturen wie Arrays und Traversable-Objekte, die mit foreach durchlaufen werden können. Alles über Typen und Generatoren.

Einführung in PHP Iterables

In PHP ist ein Iterable alles, was sich mit foreach durchlaufen lässt. Dazu gehören zwei Arten von Werten:

  1. Arrays — die alltägliche Datenstruktur, die eine geordnete Sammlung von Schlüssel/Wert-Paaren enthält.
  2. Traversable-Objekte — Objekte, die PHP durchlaufen kann, weil sie das eingebaute Traversable-Interface implementieren (in der Praxis über Iterator oder IteratorAggregate, oder als Generator).

PHP 7.1 hat den iterable-Pseudo-Typ eingeführt, damit man deklarieren kann „gib mir alles, worüber ich mit foreach iterieren kann", ohne sich darum zu kümmern, ob der Aufrufer ein Array oder ein Objekt übergibt. Diese Seite erklärt, was als Iterable gilt, wie man die einzelnen Arten erstellt und durchläuft und wann man zu den Lazy Iterables greift, die Generatoren bieten.

Dieses Kapitel baut auf PHP Arrays und der foreach-Schleife auf. Falls du mit einem der beiden noch nicht vertraut bist, lies diese zuerst.

Arrays: das gebräuchlichste Iterable

Arrays gibt es in zwei Varianten, und der einzige Unterschied liegt im Typ des verwendeten Schlüssels:

  • Ein indiziertes Array speichert Werte unter automatisch vergebenen Integer-Schlüsseln, beginnend bei 0. Siehe Indexed Arrays.
  • Ein assoziatives Array verwendet Strings (oder selbst gewählte Integer) als Schlüssel. Siehe Associative Arrays.

Ein einzelnes Array kann beide Stile mischen, und die Werte können jeden Datentyp haben.

Arrays erstellen und darauf zugreifen

Ein Array wird mit eckigen Klammern erstellt, und auf einen Wert greift man über seinen Schlüssel zu:

PHP Array definieren und darauf zugreifen

<?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 Doe

Ausgabe:

apple
John Doe

Beachte, dass indizierte Arrays nullbasiert sind, d. h. $fruits[0] ist das erste Element.

Mit foreach über ein Array iterieren

foreach ist die idiomatische Methode, um ein Iterable zu durchlaufen. Bei einem indizierten Array benötigt man in der Regel nur den Wert; bei einem assoziativen Array braucht man typischerweise sowohl Schlüssel als auch Wert:

PHP über Arrays iterieren

<?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";
}

Ausgabe:

apple
banana
cherry
name: John Doe
age: 25

Hilfreiche Array-Funktionen

PHP bietet Dutzende von Array-Funktionen. Ein paar davon werden ständig gebraucht:

  • array_keys($arr) — gibt alle Schlüssel als neues Array zurück.
  • array_values($arr) — gibt alle Werte zurück, neu indiziert ab 0.
  • count($arr) — gibt die Anzahl der Elemente zurück.
  • sort($arr) — sortiert die Werte aufsteigend in place und gibt bei Erfolg true zurück (nicht das sortierte Array).
  • in_array($needle, $arr)true, wenn der Wert vorhanden ist.

PHP Array-Funktionen in Aktion

<?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]

Ausgabe:

3
Array
(
    [0] => 0
    [1] => 1
    [2] => 2
)
Array
(
    [0] => 10
    [1] => 30
    [2] => 40
)

Der iterable-Pseudo-Typ

iterable ist keine Klasse — es ist ein Typ-Hinweis, der bedeutet „Array oder Traversable". Verwende ihn als Parameter- oder Rückgabetyp, wenn eine Funktion nur über Daten iterieren muss und man Aufrufer nicht zwingen will, ihre Daten zuerst in ein einfaches Array umzuwandeln.

PHP iterable-Typ-Hinweis

<?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 too

Ausgabe:

6
6

Der Vorteil: sumAll() akzeptiert ein gewöhnliches Array und einen lazy generierten Stream ohne zusätzlichen Code. Mehr zu Typ-Hinweisen findest du unter PHP Functions.

Generatoren: Lazy Iterables

Ein Generator ist eine Funktion, die yield anstelle von return verwendet. Sie liefert Werte einen nach dem anderen, nur wenn die Schleife den nächsten anfordert, und baut daher niemals die gesamte Kollektion im Speicher auf. Das ist ideal für große oder unendliche Sequenzen.

PHP Generator-Beispiel

<?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";

Ausgabe:

1 2 3 4 5

Da nichts gespeichert wird, benötigt range_lazy(1, 1_000_000) genauso wenig Speicher wie range_lazy(1, 5).

Benutzerdefinierte Iterable-Objekte mit Iterator

Wenn man volle Kontrolle darüber haben möchte, wie ein Objekt durchlaufen wird, implementiert man das Iterator-Interface. Es erfordert fünf Methoden, die foreach im Hintergrund aufruft: rewind(), valid(), current(), key() und next().

PHP benutzerdefinierter 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";

Ausgabe:

2 4 6

Meistens ist ein Generator einfacher als eine vollständige Iterator-Klasse — greife zu Iterator nur dann, wenn du benutzerdefiniertes Rewind/Key-Verhalten benötigst oder die Iteration als Teil der öffentlichen API eines Objekts bereitstellen möchtest.

Prüfen, ob ein Wert iterable ist

Verwende is_iterable(), um zur Laufzeit zu prüfen, ob ein Wert an foreach übergeben werden kann:

PHP is_iterable-Prüfung

<?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)

Ausgabe:

bool(true)
bool(false)
bool(true)

Fazit

„Iterable" in PHP bedeutet schlicht mit foreach durchlaufbar — und das umfasst Arrays, Iterator/IteratorAggregate-Objekte und Generatoren gleichermaßen. Verwende einfache Arrays für gewöhnliche Sammlungen, den iterable-Typ-Hinweis, um Funktionen zu schreiben, die jeden dieser Typen akzeptieren, und Generatoren, wenn Speicher eine Rolle spielt oder die Sequenz groß ist. Mit diesen Werkzeugen kannst du Daten effizient modellieren und deine APIs flexibel halten.

Übungen

Übung
Was kann in PHP als Iterable betrachtet werden?
Was kann in PHP als Iterable betrachtet werden?
Was this page helpful?