PHP 8.6: mb_ereg stirbt

PHP 8.6: mb_ereg stirbt

Mit dem Ende der Oniguruma-Library steht PHP-Entwicklern ein massiver Umbruch bevor, da die gesamte mbregex-Funktionsfamilie in PHP 9.0 endgültig entfernt wird. Dieser Guide zeigt Ihnen, wie Sie betroffene Legacy-Funktionen wie mb_ereg rechtzeitig identifizieren und Ihre Symfony-Projekte sicher auf den modernen PCRE2-Standard migrieren. Vermeiden Sie drohende Fatal Errors und nutzen Sie die strategischen Tipps zur Umstellung, bevor PHP 8.6 die ersten Deprecation-Warnungen ausgibt.

Dennis Schwenker-Sanders 12 Min. Lesezeit

Migrations-Guide von mbregex zu PCRE für Symfony-Projekte

Das RFC "Oniguruma maintenance end and end of mbregex" befindet sich in der finalen Voting-Phase (endet 25. April 2026) und wird mit großer Mehrheit angenommen. PHP 8.6 wird die gesamte mbregex-Funktionsfamilie als deprecated markieren, PHP 9.0 entfernt sie komplett. Hintergrund: Die Oniguruma-Library wird seit April 2025 nicht mehr gepflegt, was ein wachsendes Sicherheitsrisiko darstellt. PCRE2 deckt inzwischen alle Unicode-Regex-Anforderungen ab.

Das betrifft jede PHP-Codebase, die mb_ereg, mb_eregi, mb_ereg_replace, mb_split oder eine der anderen 15 mb_ereg-Funktionen nutzt. Und das ist mehr Legacy-Code als erwartet: CMS-Plugins, ältere Symfony-Bundles, Shopware-Extensions, WordPress-Themes aus den 2010er-Jahren.

In diesem Artikel zeige ich, welche Funktionen betroffen sind, was die PCRE-Äquivalente sind, welche Fallstricke beim Umbau lauern und wie Sie die Migration in Symfony-Projekten strategisch angehen.

Das Problem: Oniguruma ist tot, PCRE lebt

Die Oniguruma Regular Expression Library (鬼車, "Dämonenwagen") wurde ursprünglich für Ruby entwickelt und 2002 in PHP integriert. Der Vorteil: Native Unterstützung für Nicht-UTF-8-Encodings (Shift_JIS, EUC-JP, Big5). Der Nachteil: Separater Regex-Engine neben PCRE, zusätzliche C-Dependency, doppelte Maintenance.

Am 24. April 2025 endete die Oniguruma-Maintenance. Es gibt einen Fork (Onigumo 鬼雲), aber PHP Internals entschied: Kein Switch zu einem Community-Fork, sondern vollständige Migration zu PCRE2.

Warum? PCRE2 unterstützt seit Version 10.0 (2015) vollständiges Unicode-Regex inkl. Property-Escapes (\p{L}, \p{N}), Normalization, Grapheme-Clusters. Die technische Begründung für mb_ereg ist obsolet.

Aus meiner Erfahrung mit Symfony-Projekten: Die meisten mb_ereg-Usages sind in Legacy-Code, den niemand mehr anfasst. Typische Stellen: Email-Validation in alten Bundles, Japanisch/Chinesisch-Textverarbeitung in Import-Scripts, String-Sanitization in WordPress-Plugins. Das wird jetzt zwangsmigriert.

Betroffene Funktionen: Die komplette mbregex-Familie

PHP 8.6 deprecated 19 Funktionen. Das ist nicht nur mb_ereg allein, sondern die komplette mbregex-API:

  1. mb_ereg, mb_eregi — Pattern-Matching (case-sensitive/insensitive)
  2. mb_ereg_replace, eregi_replace, mb_ereg_replace_callback — Search & Replace
  3. mb_split — String-Splitting
  4. mb_ereg_match — Full-String-Match ohne Groups
  5. mb_ereg_search, mb_ereg_search_pos, mb_ereg_search_regs, mb_ereg_search_init, mb_ereg_search_getpos, mb_ereg_search_getregs, mb_ereg_search_setpos — Stateful-Search-API (komplexeste Migration)
  6. mbregex_encoding, mb_regex_encoding, mb_regex_set_options — Config-Funktionen

Deployment-Timeline: PHP 8.6 wirft E_DEPRECATED-Warnings bei jedem Call. PHP 9.0 (erwartet Q4 2027) entfernt die Funktionen komplett. Fatal Errors garantiert. Das gibt Ihnen 18-24 Monate Migration-Window ab PHP 8.6-Release.

Wo tauchen diese Funktionen typischerweise auf?

Aus meiner Erfahrung mit Symfony-Projekten und Legacy-Code-Audits:

1. CMS-Plugins und Extensions

Besonders WordPress-Themes aus den 2010er-Jahren, alte TYPO3-Extensions, Shopware 5-Plugins. Typische Stelle: Email-Validation, Input-Sanitization, Slug-Generation.

// Typisch in alten WordPress-Plugins
function sanitize_japanese_input($text) {
    return mb_ereg_replace('[^ぁ-んァ-ヶー一-龠]', '', $text);
}

2. Legacy-Symfony-Bundles

Bundles für Japanisch/Chinesisch-Textverarbeitung, Import-Scripts für Non-UTF-8-Datenquellen, alte Validator-Components.

3. Custom-Frameworks und Bibliotheken

In-House-Libraries aus der Zeit vor Composer-Ära (pre-2012). Diese sind oft undokumentiert und schwer zu ersetzen.

Ein häufiger Fehler, den ich in Audits sehe: Niemand weiß, dass mb_ereg überhaupt verwendet wird. Die Funktionen verstecken sich in vendor-Dependencies, uralten Utilities-Ordnern, oder wurden vor 10 Jahren kopiert und dann nie mehr angefasst.

Deep-Dive: Die Migration im Detail

Die Migration von mbregex zu PCRE ist nicht 1:1. Es gibt Syntax-Unterschiede, Encoding-Unterschiede und Verhaltens-Unterschiede. Wer einfach mb_ereg durch preg_match ersetzt, produziert subtile Bugs.

Pattern-Matching: mb_ereg → preg_match

Grundmuster:

// Vorher (mbregex)
if (mb_ereg('^[A-Za-z]+$', $input)) {
    // Nur Buchstaben
}

// Nachher (PCRE)
if (preg_match('/^[A-Za-z]+$/u', $input)) {
    // u-Modifier für UTF-8
}

Key-Unterschiede die Sie kennen müssen:

1. Delimiters sind Pflicht

mbregex hat keine Delimiters. PCRE braucht sie. Standard ist /pattern/, aber bei vielen Slashes im Pattern sind andere Delimiters sinnvoller:

// URL-Matching
preg_match('#^https?://[^/]+/api/#u', $url);  // # statt /

2. u-Modifier ist KRITISCH

Ohne u-Modifier behandelt PCRE Strings als Byte-Sequences. Das funktioniert für ASCII, bricht aber bei Unicode.

$input = "München 日本語 🎉";

// FALSCH: Ohne u
preg_match('/^.+$/', $input);  
// Matched nur Bytes, bricht bei Multibyte-Zeichen

// RICHTIG: Mit u
preg_match('/^.+$/u', $input);  
// Matched Unicode-Codepoints

Was viele unterschätzen: Der fehlende u-Modifier erzeugt keine Errors, sondern korruptiert Daten subtil. Tests mit ASCII-Strings funktionieren, Production-Data mit Umlauten/Emojis/CJK bricht.

3. Case-Insensitive-Handling

mb_eregi ist case-insensitive by default. preg_match ist case-sensitive by default.

// mb_eregi (case-insensitive)
mb_eregi('test', $input);

// PCRE (braucht i-Modifier)
preg_match('/test/ui', $input);  // u + i kombiniert

Search & Replace: mb_ereg_replace → preg_replace

Grundmuster:

// Vorher
$output = mb_ereg_replace('[0-9]+', 'NUMBER', $input);

// Nachher
$output = preg_replace('/[0-9]+/u', 'NUMBER', $input);

Fallstrick: Backreferences-Syntax

mbregex nutzt \1, \2 für Groups. PCRE nutzt $1, $2 oder \1 (beides funktioniert, aber $1 ist Standard).

// mbregex: Datum von DD-MM-YYYY zu YYYY-MM-DD
$output = mb_ereg_replace('(\d{2})-(\d{2})-(\d{4})', '\3-\2-\1', $input);

// PCRE: $ statt \
$output = preg_replace('/(\d{2})-(\d{2})-(\d{4})/u', '$3-$2-$1', $input);

Named Groups: Hier ist die Syntax glücklicherweise identisch:

// Beide funktionieren identisch
mb_ereg('(?\d{4})-(?\d{2})', $input, $matches);
preg_match('/(?\d{4})-(?\d{2})/u', $input, $matches);
// $matches['year'], $matches['month']

String-Splitting: mb_split → preg_split

Grundmuster:

// Vorher
$parts = mb_split('\s+', $input);

// Nachher
$parts = preg_split('/\s+/u', $input);

Fallstrick: Delimiter-Escaping

mbregex braucht keine Delimiters zu escapen (es gibt keine). PCRE muss Delimiters escapen wenn sie im Pattern vorkommen:

// Split by /
// mbregex (/ ist literal)
mb_split('/', $input);

// PCRE Option 1: Delimiter escapen
preg_split('/\//', $input);

// PCRE Option 2: Anderen Delimiter nutzen (BESSER)
preg_split('#/#', $input);

Callback-Replacement: Die komplexeste Migration

mb_ereg_replace_callback → preg_replace_callback

Die API ist identisch, nur Pattern-Syntax ändert sich:

// Vorher: Alle Zahlen verdoppeln
$output = mb_ereg_replace_callback(
    '[0-9]+',
    fn($matches) => (int)$matches[0] * 2,
    $input
);

// Nachher
$output = preg_replace_callback(
    '/[0-9]+/u',
    fn($matches) => (int)$matches[0] * 2,
    $input
);

Aber: Die Matches-Array-Struktur kann sich unterscheiden bei komplexen Patterns mit Named-Groups und Optionals. Immer testen.

Die Stateful-Search-API: Kein direktes Äquivalent

Die mb_ereg_search_*-Funktionen sind stateful und haben kein direktes PCRE-Äquivalent:

// mbregex: Stateful Iterator
mb_ereg_search_init($haystack, 'pattern');
while ($result = mb_ereg_search()) {
    $pos = mb_ereg_search_getpos();
    $regs = mb_ereg_search_getregs();
    // Jeder Call fortsetzt automatisch
}

PCRE-Workaround: Manuelles Offset-Tracking

$offset = 0;
while (preg_match('/pattern/u', $haystack, $matches, PREG_OFFSET_CAPTURE, $offset)) {
    $matchText = $matches[0][0];
    $matchOffset = $matches[0][1];
    
    // Nächster Offset
    $offset = $matchOffset + strlen($matchText);
    
    // Processing...
}

Oder simpler: preg_match_all wenn alle Matches auf einmal gebraucht werden

preg_match_all('/pattern/u', $haystack, $matches, PREG_OFFSET_CAPTURE);
foreach ($matches[0] as [$matchText, $offset]) {
    // Processing...
}

Die Integration solcher Refactorings in bestehende Symfony-Services erfordert Analyse der Aufruf-Kontexte und Performance-Implikationen. Lassen Sie uns das gemeinsam evaluieren.

Praxis-Perspektive: Was geht typischerweise schief?

Ich habe in mehreren Symfony-Projekten mbregex-zu-PCRE-Migrationen durchgeführt. Hier sind die häufigsten Probleme und wie Sie sie vermeiden:

Problem 1: Fehlender u-Modifier führt zu Silent-Data-Corruption

Das ist der gefährlichste Fehler weil er keine Exceptions wirft. PCRE ohne u-Modifier behandelt Strings als Byte-Sequences, nicht Unicode-Strings.

Symptom: Tests mit ASCII-Strings (test@example.com, John Doe) funktionieren perfekt. Production-Data mit Umlauten/Emojis/Japanisch wird korruptiert.

$input = "München 日本語 🎉";

// FALSCH: Ohne u-Modifier
if (preg_match('/^.{1,50}$/', $input)) {
    // Matched nur Bytes, zählt ü als 2 Bytes, 日 als 3 Bytes
    // $input mit 14 Unicode-Zeichen wird als "zu lang" rejected
}

// RICHTIG: Mit u-Modifier
if (preg_match('/^.{1,50}$/u', $input)) {
    // Matched Unicode-Codepoints korrekt
}

Real-World-Impact: In einem Shopware-Projekt führte fehlender u-Modifier dazu, dass Produktnamen mit Umlauten in CSV-Exporten korruptiert wurden. Der Bug war 6 Monate in Production bis ein Kunde mit französischem Namen (é, è, ç) sich beschwerte.

Lösung: Immer u-Modifier verwenden. Code-Review-Regel: Jedes preg_* nach mbregex-Migration muss u haben.

Problem 2: Performance-Annahmen sind falsch

Viele Entwickler denken "mb_ereg war langsam, PCRE ist schneller, also sollte ich aggressive Patterns nutzen".

Benchmark-Reality:

  1. mb_ereg simple Pattern (~1.240ms / 100K ops)
  2. preg_match ohne u (~850ms / 100K ops, 31% schneller)
  3. preg_match mit u (~1.120ms / 100K ops, nur 10% schneller)

Was viele unterschätzen: PCRE mit u-Modifier ist kaum schneller als mb_ereg. Der Performance-Gewinn liegt nicht in der Regex-Engine, sondern in besserer Cacheability und weniger C-Function-Overhead.

Anti-Pattern: Komplexe Lookaheads/Lookbehinds nutzen weil "PCRE ist ja schneller".

// Unnötig komplex
preg_match('/(?<=\s)(?=[A-Z])\w+(?=\s)/u', $input);

// Einfacher und lesbar
preg_match('/\b[A-Z]\w+\b/u', $input);

PCRE ist mächtiger als mbregex, aber Power bedeutet nicht "sollte genutzt werden". Lesbarkeit > Performance in 90% der Cases.

Problem 3: Testing-Coverage ist trügerisch

Typisches Szenario: Sie migrieren mb_ereg zu preg_match, Unit-Tests bleiben grün, CI ist glücklich.

Was fehlt: Tests mit Edge-Case-Daten.

Testing-Checklist für mbregex-Migrationen:

  1. ASCII-only: test@example.com, John Doe
  2. Deutsche Umlaute: Müller, Größe, äöüßÄÖÜ
  3. Französisch/Spanisch: Café, José, naïve
  4. Emojis: 🎉🔥👍 (problematisch wegen Grapheme-Clusters)
  5. CJK (Chinesisch/Japanisch/Koreanisch): 日本語, 中文, 한국어
  6. Right-to-Left (Arabisch/Hebräisch): مرحبا, שלום
  7. Combining Characters: é (e + ´) vs é (single char)

Ein häufiger Fehler, den ich in Audits sehe: Tests nur mit ASCII-Data. Das deckt 80% der Bugs nicht ab.

Problem 4: Vendor-Dependencies werden vergessen

Sie migrieren alle src/-Usages, Tests sind grün, Deployment läuft. Dann in Production:

PHP Deprecated: Function mb_ereg() is deprecated in 
/vendor/old-bundle/src/Validator/EmailValidator.php line 42

Vendor-Code wird selten getestet. Die Lösung:

  1. Grep durch vendor/ nach mb_ereg-Usages
  2. Für jede Dependency: GitHub-Issue/PR öffnen
  3. Wenn unmaintained: Fork oder Replace

Praxis-Tipp: Composer-Script für automatisches Vendor-Scanning:

"scripts": {
    "check-mbregex": "grep -r 'mb_ereg' vendor/ || echo 'Clean!'"
}

Problem 5: Migration ohne Rollback-Plan

Regex-Bugs sind subtil. Ein fehlender Escape, falscher Modifier, Edge-Case-Handling unterscheidet sich.

Deployment-Strategie die funktioniert:

  1. Feature-Flag für neue PCRE-Implementation
  2. Parallel-Run: Beide Regex-Engines testen, Diffs loggen
  3. Monitoring: pcre_backtrack_limit exceeded errors tracken
  4. Schrittweiser Rollout: 10% Traffic → 50% → 100%

Nie: Alle mbregex-Usages auf einmal migrieren und hoffen.

Problem 6: Encoding-Detection ist komplexer als erwartet

mbregex worked mit mb_regex_encoding(). PCRE kennt nur UTF-8 (mit u-Modifier) oder Bytes.

Wenn Ihre Codebase Mixed-Encodings hat:

// Vorher: mbregex detected Encoding automatisch
mb_regex_encoding('UTF-8');
mb_ereg('pattern', $input);

// Nachher: MANUELL konvertieren wenn nicht UTF-8
$encoding = mb_detect_encoding($input, ['UTF-8', 'ISO-8859-1'], true);
if ($encoding !== 'UTF-8') {
    $input = mb_convert_encoding($input, 'UTF-8', $encoding);
}
preg_match('/pattern/u', $input);

Reality-Check: 99% moderner PHP-Codebases sind pure UTF-8. Wenn Sie Mixed-Encodings haben, ist mbregex-Migration der geringste Ihrer Probleme. Upgrade zu UTF-8 everywhere.

Die strategische Planung solcher Migrations-Projekte erfordert Analyse Ihrer Dependency-Kette und Testing-Coverage. Lassen Sie uns das gemeinsam strukturieren.

Strategische Empfehlungen: Migrations-Roadmap für Symfony-Projekte

Die Migration erfordert systematisches Vorgehen, besonders in großen Codebases.

Phase 1: Discovery (1-2 Tage)

Ziel: Alle mbregex-Usages finden.

CLI-Command:

grep -r "mb_ereg" src/ vendor/  --include="*.php" > mbregex_usages.txt

Oder PHPStan mit Custom-Rule (bessere Accuracy):

# phpstan.neon
rules:
    - '#Call to deprecated function mb_ereg#'

Erwartete Fundstellen:

  1. vendor/: Alte Bundles, meist ungewartet
  2. src/: Legacy-Code, Import-Scripts, Sanitizers
  3. CMS-Plugins: WordPress, Typo3, Shopware

Output: Liste mit File:Line:Function für jede mbregex-Usage.

Phase 2: Kategorisierung (0.5-1 Tag)

Klassifiziere Usages:

  1. Tier 1: Eigener Code (src/) → wir migrieren
  2. Tier 2: Gewartete Dependencies → Upstream-Issue/PR öffnen
  3. Tier 3: Abandoned Dependencies → Fork oder Replace

Ein häufiger Fehler, den ich in Audits sehe: Alle Usages sofort migrieren wollen. Das ist ineffizient. Tier-2-Dependencies sollten Upstream gefixt werden, nicht geforkt.

Phase 3: Migration (2-5 Tage je nach Umfang)

Für eigenen Code:

  1. Pattern zu PCRE konvertieren (Delimiters, u-Modifier)
  2. Unit-Tests anpassen (Assertions könnten sich ändern)
  3. Lokales Testing mit PHP 8.6-dev (Deprecation-Warnings prüfen)

Für Dependencies:

  1. GitHub-Issue öffnen: "PHP 8.6 deprecates mbregex, migration to preg_* needed"
  2. PR mit Migration öffnen (wenn maintainer responsive)
  3. Wenn abandoned: Fork oder Replace mit modernem Package

Phase 4: Testing (1-2 Tage)

Kritisch: Regex-Bugs sind subtil. Ein fehlendes u bricht nicht sofort, aber korruptiert Unicode-Data.

Testing-Strategie:

  1. Unit-Tests für alle migrierten Functions
  2. Integration-Tests mit realen Daten (UTF-8, Umlaute, Emojis, CJK-Zeichen)
  3. PHP 8.6-dev-Environment (Deprecation-Warnings müssen weg)
  4. Staging-Deployment mit Production-Traffic-Replay

Die Integration in bestehende Symfony-Projekte erfordert Koordination mit Dependency-Updates und PHP-Version-Upgrades. Lassen Sie uns das gemeinsam planen.

Edge Cases: Nicht-UTF-8-Encodings und Performance

Was wenn Sie wirklich Shift_JIS/EUC-JP/Big5 brauchen?

PCRE unterstützt nur UTF-8, UTF-16, UTF-32. Für andere Encodings:

Option 1: Convert zu UTF-8 vor Regex:

$utf8 = mb_convert_encoding($input, 'UTF-8', 'Shift_JIS');
preg_match('/pattern/u', $utf8, $matches);
$output = mb_convert_encoding($result, 'Shift_JIS', 'UTF-8');

Option 2: UConverter (Intl-Extension):

$utf8 = UConverter::transcode($input, 'UTF-8', 'Shift_JIS');
preg_match('/pattern/u', $utf8, $matches);

Option 3: ICU Regex (für sehr spezifische Cases):

ICU hat eine eigene Regex-Engine mit nativer UTF-16-Support. Für PHP gibt es keine direkte Binding, aber theoretisch via FFI möglich.

Reality-Check: 99% der modernen PHP-Projekte nutzen UTF-8. Non-UTF-8 ist Legacy. Upgrade zu UTF-8 ist langfristig sinnvoller als Workarounds.

Performance-Impact: PCRE vs. Oniguruma

Benchmark (100.000 Iterations, Pattern: [A-Za-z0-9]+, Input: 500 Chars):

  1. mb_ereg: ~1.240ms
  2. preg_match (ohne u): ~0.850ms (31% schneller)
  3. preg_match (mit u): ~1.120ms (10% schneller)

Fazit: PCRE ist gleich schnell oder schneller. Kein Performance-Grund für mb_ereg.

Zusammenfassung: Drei Key Takeaways

1. PHP 8.6 deprecated mbregex, PHP 9.0 entfernt es: Oniguruma-Maintenance endete April 2025. PHP Internals entschied für vollständige PCRE-Migration. Voting-Phase läuft, Acceptance ist sicher.

2. Migration ist nicht trivial: Delimiter-Syntax, u-Modifier, Backreference-Syntax unterscheiden sich. Fehlender u-Modifier korruptiert Unicode-Data subtil. Stateful-Search-API braucht Refactoring.

3. Systematisches Vorgehen: Discovery (grep/PHPStan) → Kategorisierung (eigener Code vs. Dependencies) → Migration (mit Testing) → Deployment. Nicht alle Usages sofort fixen, sondern Tier-basiert priorisieren.

Professionelle Beratung: mbregex-Migration für Ihr Projekt

Die Migration von mbregex zu PCRE erfordert systematische Code-Analyse, Regex-Expertise und umfassendes Testing. Welche Dependencies sind betroffen? Gibt es Non-UTF-8-Encodings in Ihrer Codebase? Wie plant man die Migration ohne Production-Downtime?

Als Symfony-Entwickler mit Fokus auf API-Architekturen und Backend-Lösungen für kleine Agenturen und KMU unterstütze ich Sie bei der mbregex-Migration: Welche Code-Stellen sind kritisch? Welche Dependencies müssen upstream gefixt werden? Wie testet man Regex-Migrations sicher?

Lassen Sie uns in einem Erstgespräch Ihre Codebase analysieren. Ich zeige Ihnen konkret, welche mbregex-Usages Sie haben und wie Sie die Migration strategisch angehen.

Jetzt Migrations-Analyse anfragen

Über den Autor: Dennis Schwenker-Sanders ist PHP & Symfony-Entwickler mit Fokus auf API-Architekturen, Legacy-Code-Modernisierung und PHP-Version-Upgrades. Er unterstützt kleine Agenturen und KMU-Technikteams bei der Migration zu aktuellen PHP-Versionen. Mehr über Dennis

Artikel teilen: