Die PHP-Funktion ereg() galt lange Zeit als Standard für reguläre Ausdrücke, doch mit den modernen Anforderungen an Performance und Unicode-Kompatibilität ist sie inzwischen überholt. Dieser Artikel zeigt Schritt für Schritt, wie du bestehende ereg()-Aufrufe durch die aktuellen preg_*-Funktionen ersetzt und dabei typische Stolperfallen vermeidest.

Warum ereg() nicht mehr funktioniert
Die Funktion ereg() gehörte über Jahre zum Werkzeugkasten vieler PHP-Entwickler. Sie erlaubte das Suchen in Zeichenketten mittels regulärer Ausdrücke im POSIX-Format. Doch diese Zeiten sind vorbei: Mit PHP 5.3 wurde ereg() als veraltet (deprecated) markiert und seit PHP 7.0 ist sie vollständig entfernt. Wer versucht, heutigen Code mit ereg() auszuführen, erhält sofort einen Fatal Error:
Fatal error: Uncaught Error: Call to undefined function ereg()
Warum ist dieser Artikel relevant? Alte Projekte oder Scripte, die noch auf ereg(), eregi() oder ereg_replace() setzen, funktionieren mit modernen PHP-Versionen nicht mehr. Wer auf Wartbarkeit, Sicherheit und Performance Wert legt, kommt um ein Refactoring nicht herum.
Die Familie der preg_*-Funktionen auf Basis der leistungsstarken PCRE-Engine ist heute der Standard für reguläre Ausdrücke in PHP. Wie du bestehende ereg()-Skripte robust migrierst, zeigt dieser Artikel Schritt für Schritt.
Gründe für die Veraltung von ereg()
Gerade bei umfangreichen Datenverarbeitungen geraten die älteren RegEx-Funktionen schnell an ihre Leistungsgrenzen und bremsen das Skript aus.
Performance: Die preg_*-Funktionen (PCRE) arbeiten meist deutlich schneller und effizienter als ihre alten POSIX-Pendants wie ereg() oder eregi().
Funktionsumfang: Die PCRE-Syntax (Perl Compatible Regular Expressions) erlaubt komplexere Patterns. Dazu gehören zum Beispiel Lookarounds, Non-Capturing Groups und vieles mehr. POSIX ist im Vergleich schlicht zu limitiert.
Wartbarkeit und Zukunftssicherheit: Die Pflege alter Funktionen lohnt nicht. Der PHP-Kern konzentriert sich längst auf PCRE, Weiterentwicklungen finden nur dort statt.
Sicherheitsaspekte: Nicht gepflegter Altcode ist potenziell riskant, besonders wenn Regex-Muster fehlerhaft oder unsauber übernommen werden.
preg_match() und die PCRE-Engine
Mit preg_match() erhältst du Zugriff auf die leistungsstarke PCRE-Engine, die weit mehr RegEx-Funktionen und eine bessere Performance bietet als frühere Lösungen.
preg_match() prüft, ob ein String einem PCRE-Muster entspricht. Die Syntax ist flexibel, die Performance hoch und die Engine zuverlässig binärsicher. „Perl Compatible Regular Expressions“ ist der De-facto-Standard für reguläre Ausdrücke, nicht nur in PHP, sondern in vielen Programmiersprachen.
Vorteile von preg_match():
- Flexibilität durch PCRE-Syntax
- Zuverlässigkeit und Sicherheit auch bei Binärdaten
- Hohe Performance
- Viele Erweiterungen und Optionen (z.B. Modifiers)
ereg() vs. preg_match(): Die wichtigsten Unterschiede
Die größte Umstellung betrifft die verwendete Syntax: Während ältere Funktionen POSIX-Reguläre Ausdrücke erwarten, nutzt preg_match() die flexiblere Perl-Syntax. Das eröffnet neue Ausdrucksmöglichkeiten, erfordert aber auch Anpassung im Code.
Syntax der regulären Ausdrücke
- ereg(): POSIX Extended Regex (etwas weniger flexibel)
- preg_match(): PCRE-Syntax (mächtig, mehr Features)
Delimiter (Trennzeichen)
- ereg(): Kein Delimiter nötig, Muster direkt als String
- preg_match(): Delimiter zwingend (z.B.
/pattern/, #pattern#). Enthält das Pattern selbst den Delimiter, kannst du es mit preg_quote() escapen.
Case-Sensitivität
- ereg(): Häufig case-insensitiv interpretiert
- eregi(): Explizit case-insensitiv
- preg_match(): Standard: case-sensitiv, für insensitive Suche
/i-Modifier verwenden
Rückgabewerte
- ereg(): Liefert die Länge des Treffers oder false
- preg_match(): 1 (Treffer), 0 (kein Treffer), false (Fehler)
Beide können ein Array mit Treffern liefern ($regs bei ereg() und $matches bei preg_match()).
Behandlung von Binärdaten
- ereg(): Nicht binärsicher
- preg_match(): Binärsicher, auch für Unicode geeignet (
/u-Modifier)
Gierigkeit (Greediness)
Standardmäßig greifen beide „gierig“, d.h. sie matchen so viel wie möglich. PCRE erlaubt durch den ?-Modifier nicht-gierige Patterns (.*? statt .*).
POSIX-Zeichenklassen in PCRE
Ein häufiger Stolperstein bei der Migration: POSIX-Zeichenklassen wie [:alpha:] müssen in PCRE innerhalb einer zusätzlichen eckigen Klammer stehen, also [[:alpha:]]. In der Praxis sind die PCRE-Kürzel \w, \d und \s aber gängiger und kürzer:
<?php
/* POSIX-Klassen vs. PCRE-Kuerzel */
preg_match('/[[:alpha:]]+/', $sText);
preg_match('/[a-zA-Z]+/', $sText);
preg_match('/\w+/', $sText);
Tabellarische Übersicht
Die Tabelle macht deutlich, dass moderne RegEx-Funktionen nicht nur mehr Möglichkeiten bieten, sondern auch an aktuelle PHP-Versionen und Unicode-Anforderungen angepasst sind.
| Kriterium | ereg()/eregi() | preg_match() |
| Engine | POSIX Regex | PCRE (Perl Compatible Regex) |
| Delimiter | Nein | Ja (z.B. /, #, ~) |
| Syntaxumfang | Eingeschränkt | Umfangreich |
| Case-sensitivity | ereg: ja, eregi: nein | Standard: ja, Modifier: /i |
| Rückgabewerte | Länge/false | 1/0/false |
| Treffer-Array | Optional über dritten Parameter | Optional über dritten Parameter |
| Binärsicher | Nein | Ja |
| Verfügbar ab | < PHP 7.0 | PHP 4.x und aktueller |
| Status | Entfernt (ab 7.0) | Standard |
Praktische Migration: Von ereg() zu preg_match()
Bei der Migration gilt es, nicht nur die Funktionsnamen zu ersetzen, sondern vor allem die Syntax der regulären Ausdrücke sowie die notwendige Angabe eines Delimiters im Muster zu berücksichtigen.
Grundlegende Konvertierung
Der einfachste Fall: Du fügst Delimiter um das Pattern und verwendest preg_match() statt ereg():
<?php
/* Vorher (nicht mehr nutzbar) */
if (ereg("abc[0-9]+", $sText)) {
/* ... */
}
/* Nachher */
if (preg_match("/abc[0-9]+/", $sText)) {
/* ... */
}
Für die case-insensitive Variante eregi() verwendest du den /i-Modifier:
<?php
/* Vorher */
if (eregi("abc[0-9]+", $sText)) { /* ... */ }
/* Nachher */
if (preg_match("/abc[0-9]+/i", $sText)) { /* ... */ }
Mit Treffer-Array (drittes Argument)
Das Treffer-Array funktioniert bei beiden Funktionen ähnlich:
<?php
/* Vorher */
if (ereg("([a-z]+)([0-9]+)", $sText, $aTreffer)) {
/* $aTreffer[1], $aTreffer[2] */
}
/* Nachher */
if (preg_match("/([a-z]+)([0-9]+)/", $sText, $aTreffer)) {
/* $aTreffer[1], $aTreffer[2] */
}
ereg_replace() zu preg_replace()
Die Ersetzungsfunktionen werden nach dem gleichen Prinzip migriert:
<?php
/* ereg_replace */
$sNeu = ereg_replace("abc[0-9]+", "X", $sText);
$sNeu = preg_replace("/abc[0-9]+/", "X", $sText);
/* eregi_replace (case-insensitiv) */
$sNeu = eregi_replace("abc[0-9]+", "X", $sText);
$sNeu = preg_replace("/abc[0-9]+/i", "X", $sText);
split() zu preg_split() oder explode()
Die alte split()-Funktion kann durch preg_split() ersetzt werden. Wenn das Trennzeichen ein fester String ohne Regex ist, ist explode() die bessere und schnellere Wahl:
<?php
/* Vorher */
$aTeile = split(",", $sText);
/* Nachher (mit Regex) */
$aTeile = preg_split("/,/", $sText);
/* Besser (festes Trennzeichen, kein Regex) */
$aTeile = explode(",", $sText);
Braucht es überhaupt Regex? PHP 8.0+ String-Funktionen
Viele ereg()-Aufrufe in Altcode prüfen lediglich, ob ein String mit einem bestimmten Text beginnt, endet oder ob ein Teilstring enthalten ist. Für solche Fälle brauchst du seit PHP 8.0 gar keinen regulären Ausdruck mehr:
<?php
/* Vorher: Beginnt mit "abc"? */
if (ereg("^abc", $sText)) { /* ... */ }
/* Nachher: Kein Regex noetig! */
if (str_starts_with($sText, "abc")) { /* ... */ }
/* Vorher: Endet mit ".php"? */
if (ereg("\.php$", $sText)) { /* ... */ }
if (str_ends_with($sText, ".php")) { /* ... */ }
/* Vorher: Enthaelt "error"? */
if (ereg("error", $sText)) { /* ... */ }
if (str_contains($sText, "error")) { /* ... */ }
Diese Funktionen sind nicht nur lesbarer, sondern auch deutlich schneller als jeder Regex. Prüfe bei jeder Migration zuerst, ob eine einfache String-Funktion ausreicht.
preg_match_all(): Alle Treffer auf einmal finden
In Altcode findet man häufig Schleifen, die mit ereg() und einem Offset alle Vorkommen eines Musters suchen. preg_match_all() erledigt das in einem einzigen Aufruf:
<?php
$sLog = "Error 404: Nicht gefunden. Error 500: Serverfehler.";
$iAnzahl = preg_match_all("/Error ([0-9]+)/", $sLog, $aTreffer);
echo $iAnzahl; // 2
print_r($aTreffer[1]); // ["404", "500"]
preg_quote(): Benutzereingaben im Regex escapen
Wenn du einen dynamischen String als Teil eines Regex verwenden willst, muss er mit preg_quote() escaped werden. Sonderzeichen wie Punkte, Klammern oder Sterne würden sonst als Regex-Metazeichen interpretiert:
<?php
$sSuchwort = "config.php";
/* Ohne preg_quote: Punkt matcht JEDES Zeichen */
preg_match("/" . $sSuchwort . "/", $sText);
/* Mit preg_quote: Punkt wird literal gesucht */
$sEscaped = preg_quote($sSuchwort, "/");
preg_match("/" . $sEscaped . "/", $sText);
/* $sEscaped enthaelt "config\.php" */
Der zweite Parameter von preg_quote() gibt den Delimiter an, der zusätzlich escaped werden soll.
Wichtige preg_match()-Modifier
/i macht die Suche case-insensitiv (Groß/Kleinschreibung ignorieren) /u aktiviert Unicode/UTF-8-Behandlung (besonders wichtig bei deutschen Umlauten) /s lässt den Punkt auch Zeilenumbrüche matchen /m macht ^ und $ zu Zeilenanfang/-ende (Multiline)
Typische Fallstricke bei der Migration
- Delimiter vergessen:
preg_match("abc[0-9]+", $sText) fehlt der Delimiter. Korrekt: preg_match("/abc[0-9]+/", $sText) - Delimiter im Pattern: Wenn das Pattern selbst
/ enthält, nimm ein anderes Zeichen als Delimiter (z.B. # oder ~). - Modifier vergessen: Bei Suchen mit Umlauten immer
/u ergänzen. - Unterschiedliche Rückgabewerte:
ereg() liefert die Trefferlänge oder false, preg_match() liefert 1, 0 oder false. - Backslash-Escaping: In PCRE-Patterns müssen Backslashes in Double-Quotes doppelt escaped werden. Schreibe
"\\d" oder nutze Single-Quotes: '\d'.
Migrationsstrategie für große Codebasen
Wer ein umfangreiches Projekt migrieren muss, braucht einen systematischen Ansatz statt einzelner Suchen-und-Ersetzen-Aktionen.
- Alle ereg-Aufrufe finden: Durchsuche dein Projekt per IDE-Suche oder Kommandozeile nach
ereg(, eregi(, ereg_replace(, eregi_replace( und split(. - Komplexität einschätzen: Einfache Patterns (feste Strings, einfache Zeichenklassen) lassen sich schnell ersetzen. Komplexe Patterns mit Backreferences oder verschachtelten Gruppen erfordern manuelle Prüfung.
- Einfache Fälle zuerst: Prüfe bei jedem Aufruf, ob ein Regex überhaupt nötig ist. Häufig reichen
str_contains(), str_starts_with(), str_ends_with() oder strpos(). - Patterns testen: Nutze regex101.com mit dem Flavor „PCRE2 (PHP ≥ 7.3)“, um migrierte Patterns mit verschiedenen Teststrings zu validieren.
- Automatisierung prüfen: Das Refactoring-Tool Rector kann viele ereg-zu-preg-Migrationen automatisch durchführen. Für kleinere Projekte ist ein manuelles Suchen-und-Ersetzen in der IDE oft schneller.
Multibyte-Strings und mb_ereg()
Wer heute Unicode-Zeichen sicher prüfen will, sollte konsequent preg_match() mit dem /u-Modifier einsetzen, da dies Multibyte-Zeichen vollständig unterstützt und zukunftssicher ist.
mb_ereg() war Teil der Multibyte String Functions für UTF-8-Support bei POSIX-Regex. Diese Funktion existiert zwar noch in PHP 8.x, ist aber weitgehend durch PCRE mit /u abgelöst. Hier ein direkter Vergleich:
<?php
$sText = "Straße führt nach Österreich";
/* Mit mb_ereg (POSIX-Stil, noch vorhanden) */
mb_regex_encoding('UTF-8');
if (mb_ereg('[äöüß]', $sText)) {
echo "Umlaute gefunden";
}
/* Mit preg_match (empfohlen) */
if (preg_match('/[äöüß]/u', $sText)) {
echo "Umlaute gefunden";
}
Empfehlung: Setze auf preg_match() mit /u für alle Unicode/UTF-8-Prüfungen. mb_ereg() brauchst du nur, wenn du POSIX-Syntax zwingend beibehalten musst.
Code-Beispiele: Vorher/Nachher-Szenarien
Anhand konkreter Szenarien siehst du, wie die Migration in der Praxis aussieht. Bei jeder Umstellung lohnt es sich zu prüfen, ob es eine noch einfachere Lösung ohne Regex gibt.
Szenario 1: E-Mail-Prüfung
Vorher (ereg):
<?php
$sMail = "info@beispiel.de";
if (ereg("^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$", $sMail)) {
/* Gueltig */
}
Nachher (preg_match):
<?php
$sMail = "info@beispiel.de";
if (preg_match("/^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/", $sMail)) {
/* Gueltig */
}
Noch besser: Die Regex-basierte E-Mail-Prüfung ist fehleranfällig und deckt nicht alle gültigen Formate ab. Die empfohlene Methode in modernem PHP ist filter_var():
<?php
$sMail = "info@beispiel.de";
if (filter_var($sMail, FILTER_VALIDATE_EMAIL)) {
echo "Gueltige E-Mail-Adresse";
}
Für die Validierung von Formular-Eingaben bietet sich zusätzlich filter_input() an.
Szenario 2: Pfad-Teile extrahieren
<?php
$sPfad = "/var/www/html/index.php";
/* Vorher */
ereg("^/([^/]+)/([^/]+)/([^/]+)$", $sPfad, $aTeile);
/* Nachher (anderer Delimiter wegen /) */
preg_match("|^/([^/]+)/([^/]+)/([^/]+)$|", $sPfad, $aTeile);
Szenario 3: Case-insensitive Ersetzung
<?php
$sText = "Hallo Welt!";
/* Vorher */
$sNeu = eregi_replace("welt", "Erde", $sText);
/* Nachher */
$sNeu = preg_replace("/welt/i", "Erde", $sText);
/* Ergebnis: "Hallo Erde!" */
Szenario 4: URL validieren
<?php
$sUrl = "https://www.beispiel.de/seite?id=42";
/* Vorher */
if (ereg("^https?://[a-zA-Z0-9.-]+", $sUrl)) {
/* Gueltige URL */
}
/* Nachher */
if (preg_match('#^https?://[a-zA-Z0-9.-]+#', $sUrl)) {
/* Gueltige URL */
}
/* Noch besser: filter_var */
if (filter_var($sUrl, FILTER_VALIDATE_URL)) {
/* Gueltige URL */
}
Szenario 5: Postleitzahl prüfen
<?php
$sPlz = "80331";
/* Vorher */
if (ereg("^[0-9]{5}$", $sPlz)) {
/* Deutsche PLZ */
}
/* Nachher */
if (preg_match('/^\d{5}$/', $sPlz)) {
/* Deutsche PLZ */
}
/* Alternative ohne Regex */
if (ctype_digit($sPlz) && strlen($sPlz) === 5) {
/* Deutsche PLZ */
}
Szenario 6: Log-Zeile bereinigen
<?php
$sLog = "2024-01-15 ERROR: Datei nicht gefunden";
/* Vorher */
$sBereinigt = ereg_replace("[0-9]{4}-[0-9]{2}-[0-9]{2}", "", $sLog);
/* Nachher */
$sBereinigt = preg_replace('/\d{4}-\d{2}-\d{2}/', '', $sLog);
/* Ergebnis: " ERROR: Datei nicht gefunden" */
Fazit
Es führt kein Weg daran vorbei: ereg() ist Geschichte. Die Vorteile von PCRE sind zu groß, um sie zu ignorieren. Wer die Migration konsequent angeht, erhält nicht nur mehr Performance und Features, sondern macht seinen Code auch sicherer und zukunftsfähig.
- Leistungsstark: Umfangreiche Regex-Syntax mit Lookarounds, Non-Capturing Groups und mehr
- Sicher: Binärsicher und Unicode-fähig
- Wartbar: Einfache, konsistente Anwendung in allen Projekten
Nutze die Gelegenheit, um bestehende Scripte von Grund auf zu prüfen und Fehlerquellen wie veraltete Regex-Patterns gleich mit zu beseitigen. Und prüfe bei jeder Migration zuerst, ob eine einfache String-Funktion wie str_contains() den Regex komplett überflüssig macht.
FAQ: Häufig gestellte Fragen
Hier findest du Antworten auf die wichtigsten Fragen rund um die Migration von ereg() zu modernen Alternativen.
Ist ereg() wirklich komplett entfernt?
Ja, seit PHP 7.0 gibt es ereg(), eregi(), ereg_replace(), eregi_replace() und split() nicht mehr. Der Aufruf führt zu einem Fatal Error.
Gibt es einen Polyfill für ereg()?
Theoretisch könnte man eine eigene ereg()-Funktion schreiben, die intern preg_match() aufruft. Das ist aber keine gute Idee: Die POSIX-Syntax unterscheidet sich an vielen Stellen von PCRE, sodass ein simpler Wrapper nicht alle Fälle abdeckt. Die direkte Migration ist sicherer.
Wie gehe ich mit Backslash-Escaping um?
In POSIX-Patterns brauchte man weniger Backslashes. In PCRE-Patterns mit Double-Quotes muss der Backslash doppelt escaped werden, weil PHP ihn zuerst interpretiert:
<?php
/* Ziffern matchen */
preg_match("/\\d+/", $sText); // Double-Quotes
preg_match('/\d+/', $sText); // Single-Quotes (einfacher)
Was ist der schnellste Weg, alten Code zu aktualisieren?
Systematisch jede ereg()-Zeile durch preg_match()/preg_replace() ersetzen, Pattern-Syntax prüfen und mit Testdaten gegenchecken. Für größere Projekte kann das Refactoring-Tool Rector die Arbeit automatisieren.
Ist preg_match() schneller als ereg()?
Ja. Die PCRE-Engine ist in den meisten Fällen deutlich schneller als die alte POSIX-Engine. Zusätzlich kompiliert PCRE die Patterns und cached sie intern, was bei wiederholten Aufrufen einen spürbaren Vorteil bringt.
Wie teste ich, ob mein migriertes Pattern korrekt funktioniert?
Nutze regex101.com und wähle im Dropdown den Flavor „PCRE2 (PHP ≥ 7.3)“. Dort kannst du dein Pattern mit verschiedenen Teststrings prüfen und siehst sofort, welche Teile matchen.
Wo finde ich mehr Infos zur PCRE-Syntax?
Die offizielle PHP-Dokumentation und regex101.com sind ideale Startpunkte.
Muss ich immer Regex verwenden?
Nein. Viele alte ereg()-Aufrufe lassen sich durch einfache String-Funktionen ersetzen. str_contains(), str_starts_with() und str_ends_with() (ab PHP 8.0) sind für einfache Prüfungen lesbarer und schneller als jeder Regex.