Reguläre Ausdrücke gehören zu den mächtigsten Werkzeugen in PHP, wenn es um die Analyse und Verarbeitung von Strings geht. Während preg_match() nur den ersten Treffer in einem String liefert, durchsucht preg_match_all() den gesamten String und sammelt sämtliche Übereinstimmungen in einem Array. Das ist besonders nützlich, wenn du alle Vorkommen eines Musters extrahieren willst, etwa alle Zahlen aus einem Text, alle E-Mail-Adressen aus einer Webseite oder alle HTML-Tags aus einem Dokument. In diesem Tutorial lernst du die Syntax von preg_match_all(), verstehst die verschiedenen Ergebnis-Strukturen und siehst zahlreiche praktische Beispiele für den Einsatz im Alltag.

Zum Einstieg schauen wir uns an, was die Funktion genau tut und wie sie sich von preg_match() unterscheidet.
Was macht preg_match_all()?
Die Funktion preg_match_all() durchsucht einen String nach allen Vorkommen eines regulären Ausdrucks. Im Gegensatz zu preg_match(), das nach dem ersten Treffer stoppt, arbeitet preg_match_all() den kompletten String von Anfang bis Ende durch. Jeder gefundene Treffer wird in einem mehrdimensionalen Array gespeichert, das nach dem Funktionsaufruf zur Verfügung steht.
Der Rückgabewert der Funktion ist die Anzahl der gefundenen Treffer als Integer. Wird kein Treffer gefunden, gibt die Funktion 0 zurück. Bei einem Fehler im Pattern oder einem anderen Problem liefert sie false. Dieser Rückgabewert lässt sich direkt in einer Bedingung verwenden, um zu prüfen, ob Übereinstimmungen vorhanden sind.
<?php
$text = 'Heute ist der 5. Mai 2026, morgen der 6. Mai 2026';
$anzahl = preg_match_all('/\d+/', $text, $treffer);
echo $anzahl; /* 4 */
print_r($treffer[0]);
/* Array ( [0] => 5 [1] => 2026 [2] => 6 [3] => 2026 ) */
Syntax und Parameter
Die vollständige Signatur von preg_match_all() umfasst fünf Parameter. Die ersten beiden sind Pflichtparameter, die übrigen drei sind optional. Im Folgenden werden alle Parameter einzeln erläutert.
preg_match_all(
string $pattern,
string $subject,
array &$matches = null,
int $flags = 0,
int $offset = 0
): int|false
Pattern (Muster)
Der erste Parameter ist der reguläre Ausdruck als String. Das Pattern muss in Delimiter eingeschlossen sein, üblicherweise Schrägstriche. Nach dem abschließenden Delimiter können Modifier folgen, etwa i für eine case-insensitive Suche oder s, damit der Punkt auch Zeilenumbrüche erfasst.
Subject (Eingabestring)
Der zweite Parameter ist der String, der durchsucht werden soll. Die Funktion arbeitet den gesamten Subject-String von Anfang bis Ende durch und sammelt alle Treffer. Es spielt keine Rolle, wie lang der String ist.
Matches (Ergebnis-Array)
Der dritte Parameter ist eine Referenz auf ein Array, in dem die Ergebnisse gespeichert werden. Nach dem Funktionsaufruf enthält dieses Array alle gefundenen Treffer. Die Struktur des Arrays hängt vom gewählten Flag ab. Wird der Parameter weggelassen, gibt die Funktion trotzdem die Anzahl der Treffer zurück.
Flags
Der vierte Parameter steuert, wie das Ergebnis-Array aufgebaut wird. Die drei wichtigsten Flags sind PREG_PATTERN_ORDER, PREG_SET_ORDER und PREG_OFFSET_CAPTURE. Standardmäßig wird PREG_PATTERN_ORDER verwendet. Die Flags lassen sich auch mit dem Bit-Operator kombinieren, etwa PREG_SET_ORDER | PREG_OFFSET_CAPTURE.
Offset
Der fünfte Parameter gibt die Position im Subject-String an, ab der die Suche beginnen soll. Der Standardwert ist 0, also der Anfang des Strings. Ein Offset von 10 bedeutet, dass die ersten zehn Zeichen übersprungen werden.
Die Ergebnis-Struktur verstehen
Das Verständnis der Ergebnis-Struktur ist entscheidend für die effektive Arbeit mit preg_match_all(). Je nach gewähltem Flag wird das Matches-Array unterschiedlich aufgebaut. Die folgenden Abschnitte zeigen die drei wichtigsten Varianten.
flowchart TD
A["preg_match_all()"] --> B{"Welches Flag?"}
B --> C["PREG_PATTERN_ORDER"]
B --> D["PREG_SET_ORDER"]
B --> E["PREG_OFFSET_CAPTURE"]
C --> F["matches sortiert nach Gruppe"]
D --> G["matches sortiert nach Treffer"]
E --> H["matches mit Byte-Offset"]
F --> Z["Treffer verarbeiten"]
G --> Z
H --> Z
PREG_PATTERN_ORDER (Standard)
Mit dem Standard-Flag PREG_PATTERN_ORDER werden die Ergebnisse nach Gruppennummer sortiert. Das Array $matches[0] enthält alle vollständigen Treffer. $matches[1] enthält alle Treffer der ersten Capture-Gruppe, $matches[2] die der zweiten Gruppe und so weiter.
<?php
$html = '<a href="seite1.html">Link 1</a> und <a href="seite2.html">Link 2</a>';
preg_match_all('/<a href="([^"]+)">([^<]+)<\/a>/', $html, $matches);
print_r($matches[0]);
/* Alle vollstaendigen Treffer */
print_r($matches[1]);
/* Array ( [0] => seite1.html [1] => seite2.html ) */
print_r($matches[2]);
/* Array ( [0] => Link 1 [1] => Link 2 ) */
Diese Struktur eignet sich besonders gut, wenn du gezielt auf alle Werte einer bestimmten Gruppe zugreifen willst, etwa auf alle URLs oder alle Linktexte.
PREG_SET_ORDER
Mit dem Flag PREG_SET_ORDER werden die Ergebnisse nach Treffer sortiert. Jeder Eintrag im Array enthält den vollständigen Treffer und seine Gruppen als zusammengehöriges Set. $matches[0] enthält den ersten Treffer mit allen seinen Gruppen, $matches[1] den zweiten Treffer und so weiter.
<?php
$html = '<a href="seite1.html">Link 1</a> und <a href="seite2.html">Link 2</a>';
preg_match_all('/<a href="([^"]+)">([^<]+)<\/a>/', $html, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
echo 'URL: ' . $match[1] . ' Text: ' . $match[2];
}
/* URL: seite1.html Text: Link 1 */
/* URL: seite2.html Text: Link 2 */
Diese Struktur ist ideal für die Verarbeitung mit foreach, weil jeder Schleifendurchlauf einen zusammengehörigen Datensatz liefert.
PREG_OFFSET_CAPTURE
Das Flag PREG_OFFSET_CAPTURE erweitert jeden Treffer um seine Position im Subject-String. Statt eines einfachen Strings enthält jeder Eintrag ein Array mit zwei Elementen: dem gefundenen Text und seiner Startposition als Byte-Offset.
<?php
$text = 'PHP 8.3 und PHP 8.4 sind aktuell';
preg_match_all('/PHP \d+\.\d+/', $text, $matches, PREG_OFFSET_CAPTURE);
foreach ($matches[0] as $treffer) {
echo $treffer[0] . ' an Position ' . $treffer[1];
}
/* PHP 8.3 an Position 0 */
/* PHP 8.4 an Position 16 */
Dieses Flag ist besonders nützlich, wenn du wissen musst, wo genau im String ein Treffer auftritt, etwa für Syntax-Highlighting oder die Hervorhebung von Suchbegriffen.
Praktische Beispiele
Die folgenden Beispiele zeigen typische Anwendungsfälle von preg_match_all() im Entwickleralltag. Jedes Beispiel verwendet ein anderes Pattern und demonstriert eine andere Herangehensweise.
Alle Zahlen aus einem Text extrahieren
Ein häufiger Anwendungsfall ist das Extrahieren aller Zahlen aus einem gemischten Text. Das Pattern \d+ findet Folgen von einer oder mehreren Ziffern.
<?php
$text = 'Artikel 42 kostet 19 Euro und wiegt 3 Kilogramm';
$anzahl = preg_match_all('/\d+/', $text, $matches);
echo 'Gefundene Zahlen: ' . $anzahl;
/* Gefundene Zahlen: 3 */
$summe = array_sum($matches[0]);
echo 'Summe: ' . $summe;
/* Summe: 64 */
HTML-Tags finden
Das Auffinden von HTML-Tags ist ein klassisches Einsatzgebiet für reguläre Ausdrücke. Das folgende Beispiel extrahiert alle öffnenden Tags einschließlich ihrer Attribute.
<?php
$html = '<div class="box"><p>Text</p><span id="info">Info</span></div>';
preg_match_all('/<(\w+)[^>]*>/', $html, $matches);
print_r($matches[0]);
/* Alle oeffnenden Tags mit Attributen */
print_r($matches[1]);
/* Array ( [0] => div [1] => p [2] => span ) */
Die erste Capture-Gruppe (\w+) erfasst dabei nur den Tag-Namen ohne Attribute. So lassen sich die Tag-Namen separat auswerten.
E-Mail-Adressen extrahieren
Das Extrahieren von E-Mail-Adressen aus einem Text ist ein weiterer typischer Anwendungsfall. Das Pattern nutzt Zeichenklassen, um die Struktur einer E-Mail-Adresse abzubilden.
<?php
$text = 'Kontakt: info@example.com oder support@firma.de fuer Anfragen';
preg_match_all('/[\w.+-]+@[\w-]+\.[\w.]+/', $text, $matches);
foreach ($matches[0] as $email) {
echo $email;
}
/* info@example.com */
/* support@firma.de */
Ergebnisse mit foreach durchlaufen
Die Kombination von preg_match_all() mit einer foreach-Schleife ist der übliche Weg, um alle gefundenen Treffer zu verarbeiten. Dabei empfiehlt sich das Flag PREG_SET_ORDER, weil es die Daten trefferbezogen gruppiert und so den Zugriff in der Schleife vereinfacht.
<?php
$csv = 'Max Mustermann (42), Erika Muster (37), Hans Beispiel (55)';
preg_match_all('/(\w+ \w+) \((\d+)\)/', $csv, $matches, PREG_SET_ORDER);
foreach ($matches as $person) {
echo 'Name: ' . $person[1] . ', Alter: ' . $person[2];
}
/* Name: Max Mustermann, Alter: 42 */
/* Name: Erika Muster, Alter: 37 */
/* Name: Hans Beispiel, Alter: 55 */
Mit PREG_PATTERN_ORDER müsstest du stattdessen über einen Index iterieren und auf $matches[1][$i] sowie $matches[2][$i] zugreifen, was den Code weniger übersichtlich macht. Verwende daher PREG_SET_ORDER, wenn du die Treffer einzeln in einer Schleife verarbeiten willst.
preg_match() vs. preg_match_all()
Beide Funktionen verwenden dieselbe Pattern-Syntax und arbeiten mit denselben Modifiern. Der entscheidende Unterschied liegt im Suchverhalten. preg_match() stoppt nach dem ersten Treffer und gibt 1 oder 0 zurück. preg_match_all() durchsucht den gesamten String und gibt die Gesamtzahl aller Treffer zurück.
<?php
$text = 'rot, blau, gruen, rot, gelb';
/* preg_match findet nur den ersten Treffer */
$ergebnis1 = preg_match('/\w+/', $text, $match);
echo $match[0]; /* rot */
/* preg_match_all findet alle Treffer */
$ergebnis2 = preg_match_all('/\w+/', $text, $matches);
echo $ergebnis2; /* 5 */
print_r($matches[0]);
/* Array ( [0] => rot [1] => blau [2] => gruen [3] => rot [4] => gelb ) */
Als Faustregel gilt: Verwende preg_match(), wenn du nur wissen willst, ob ein Muster im String vorkommt, oder wenn du nur den ersten Treffer brauchst. Verwende preg_match_all(), wenn du alle Vorkommen eines Musters sammeln und auswerten willst. Für das Ersetzen von Treffern bietet PHP die Funktion preg_replace(), die ebenfalls den gesamten String durchsucht.
Häufige Fehler und Tipps
Bei der Arbeit mit preg_match_all() treten einige typische Fehler immer wieder auf. Die folgende Liste hilft, diese zu vermeiden.
Der häufigste Fehler ist ein fehlendes oder falsches Delimiter-Zeichen. Das Pattern muss immer in Delimiter eingeschlossen sein, zum Beispiel /muster/ oder #muster#. Ohne Delimiter gibt PHP eine Warnung aus und die Funktion gibt false zurück.
Ein weiterer häufiger Fehler ist die Verwechslung von gierigen und faulen Quantifizierern. Das Pattern /<.+>/ erfasst mit dem gierigen Quantifizierer + so viel Text wie möglich, was bei mehreren Tags im String zu unerwartet großen Treffern führt. Das faule Gegenstück /<.+?>/ stoppt beim nächstmöglichen Treffer und liefert die einzelnen Tags.
Achte außerdem darauf, den Rückgabewert korrekt zu prüfen. Da die Funktion bei Fehlern false zurückgibt und bei keinem Treffer 0, solltest du für die Fehlerprüfung den strikten Vergleich === false verwenden. Ein einfacher Vergleich mit if ($ergebnis) würde sowohl 0 als auch false als falsy behandeln.
Sonderzeichen innerhalb des Patterns müssen korrekt maskiert werden. Zeichen wie Punkte, Klammern oder eckige Klammern haben in regulären Ausdrücken eine besondere Bedeutung. Wenn du nach diesen Zeichen als Literale suchen willst, musst du sie mit einem Backslash maskieren oder die Funktion preg_quote() verwenden.
Bei UTF-8-Strings empfiehlt sich der Modifier u am Ende des Patterns, also etwa /\w+/u. Ohne diesen Modifier arbeitet die Regex-Engine bytebasiert, was bei Umlauten und anderen Multibyte-Zeichen zu falschen Ergebnissen führen kann.
Fazit
Die Funktion preg_match_all() ist das zentrale Werkzeug in PHP, um alle Vorkommen eines Musters in einem String zu finden. Mit dem Standard-Flag PREG_PATTERN_ORDER erhältst du die Ergebnisse nach Gruppennummer sortiert, was den gezielten Zugriff auf einzelne Capture-Gruppen erleichtert. Für die Verarbeitung in einer foreach-Schleife eignet sich PREG_SET_ORDER besser, weil es die Daten trefferbezogen bündelt. PREG_OFFSET_CAPTURE ergänzt jeden Treffer um seine Position im String. Zusammen mit preg_match() für einzelne Treffer und preg_replace() für das Ersetzen bildet preg_match_all() das Fundament der Regex-Verarbeitung in PHP.