[Solution] PHP ereg() Deprecated — Replace with preg_match() Migration
The ereg() function was removed from PHP because PCRE (Perl Compatible Regular Expressions) provides better performance, richer features, and broader industry support. Migrating to preg_match() is straightforward once you understand the key differences in syntax. The PCRE engine used by preg_match() is faster and more secure than the old POSIX regex functions.
What You’ll See
If your code still calls ereg(), eregi(), ereg_replace(), or eregi_replace() on PHP 7.0+, you will see:
Deprecated: Function ereg() is deprecated in /path/to/script.php on line X
On PHP 7.0+, the error becomes fatal:
Fatal error: Uncaught Error: Call to undefined function ereg()
Why Deprecated
PHP deprecated all POSIX regex functions (ereg, eregi, ereg_replace, eregi_replace, split) in PHP 5.3 and removed them entirely in PHP 7.0. The PCRE extension (preg_* functions) replaced them because:
- Performance: PCRE is significantly faster for complex patterns.
- Features: PCRE supports non-greedy matching, lookaheads, named groups, and other advanced syntax.
- Industry standard: PCRE is based on Perl’s regex engine and is used across many languages and platforms.
- Security: The POSIX regex engine in PHP had known vulnerabilities with certain crafted patterns.
Old Code (Deprecated)
// Basic match with ereg
$email = "user@example.com";
if (ereg("^[a-zA-Z0-9._]+@[a-zA-Z0-9._]+$", $email)) {
echo "Valid email";
}
// Case-insensitive match with eregi
if (eregi("^hello", "Hello World")) {
echo "Starts with hello";
}
// Replace with ereg_replace
$date = "2024-01-15";
$formatted = ereg_replace("([0-9]{4})-([0-9]{2})-([0-9]{2})", "\\3/\\2/\\1", $date);
echo $formatted; // 15/01/2024
// Sub-pattern capture with ereg
if (ereg("([a-z]+)@([a-z]+)", $email, $matches)) {
echo "User: " . $matches[1] . ", Domain: " . $matches[2];
}
New Code (Replacement)
// Basic match with preg_match — note the delimiters and anchoring
$email = "user@example.com";
if (preg_match("/^[a-zA-Z0-9._]+@[a-zA-Z0-9._]+$/", $email)) {
echo "Valid email";
}
// Case-insensitive match with preg_match — use the 'i' modifier
if (preg_match("/^hello/i", "Hello World")) {
echo "Starts with hello";
}
// Replace with preg_match_replace
$date = "2024-01-15";
$formatted = preg_replace("/(\d{4})-(\d{2})-(\d{2})/", "$3/$2/$1", $date);
echo $formatted; // 15/01/2024
// Sub-pattern capture with preg_match
if (preg_match("/([a-z]+)@([a-z]+)/", $email, $matches)) {
echo "User: " . $matches[1] . ", Domain: " . $matches[2];
}
// Named capture groups (PCRE advantage)
if (preg_match("/(?P<user>[a-z]+)@(?P<domain>[a-z]+)/", $email, $matches)) {
echo "User: " . $matches['user'] . ", Domain: " . $matches['domain'];
}
Key Syntax Differences
| POSIX (Old) | PCRE (New) |
|---|---|
ereg("pattern", $str) | preg_match("/pattern/", $str) |
eregi("pattern", $str) | preg_match("/pattern/i", $str) |
ereg_replace("p", "r", $str) | preg_replace("/p/", "r", $str) |
\\1 (back-reference) | $1 or $1 in replacement |
| No delimiters required | Delimiters required (usually /) |
The most common mistake is forgetting to wrap the pattern in delimiters. Use /, ~, #, or any non-alphanumeric character that does not appear in your pattern.
Migration Steps
- Find all POSIX regex calls in your codebase:
grep -rn "ereg\|eregi\|ereg_replace\|eregi_replace" --include="*.php" /path/to/project/
Wrap every pattern in delimiters (
/pattern/). Escape any/characters inside the pattern.Replace
eregi()calls by adding theimodifier after the closing delimiter instead.Replace back-references in
ereg_replace(). Change\\1to$1in the replacement string.Test thoroughly. PCRE and POSIX regex have subtle differences in character class behavior and anchoring.
Search for leftover split() calls since
split()was also deprecated alongsideereg():
grep -rn "\bsplit\s*(" --include="*.php" /path/to/project/
For large codebases, consider using a scripted sed replacement or a tool like Rector to automate the conversion.