Regular Expressions in PHP
PHP's regular expression support is built on the PCRE (Perl Compatible Regular Expressions) library, exposed through the preg_* family of functions such as preg_match(), preg_match_all(), preg_replace(), and preg_split(). Unlike some languages where a pattern is a bare string, PHP PCRE patterns must be delimited — typically with forward slashes, e.g. /pattern/ — and can carry modifier flags after the closing delimiter, such as i for case-insensitive matching, m for multiline mode, and u for UTF-8 mode. There is an older ereg_* family, but it was removed entirely in PHP 7, so preg_* is the only regex API in modern PHP.
Cricket analogy: A DRS ball-tracking review always needs a clearly marked zone, the delimiters, around the stumps before analysis begins, and can apply modifiers like 'ignore spin bias' or 'multi-angle mode,' while the old manual umpire-only judgment system was retired entirely once technology took over.
Matching and Extracting with preg_match
preg_match() tests whether a pattern matches a string and, when passed a third argument by reference, populates it with the match details: index 0 holds the full match, and subsequent indices hold captured groups in the order their parentheses open. Named capture groups, written as (?<name>...), let you access matches by a readable key instead of a numeric index, which improves clarity considerably in patterns with several groups.
Cricket analogy: Checking if a delivery was a no-ball fills a report where slot zero is 'no-ball: yes/no' and the next slots capture specifics like foot position, or you could label it clearly as 'front-foot,' a named capture, instead of just 'slot two.'
$log = '2026-07-09 14:32:10 ERROR Database connection failed';
if (preg_match('/^(?<date>\d{4}-\d{2}-\d{2}) (?<time>\d{2}:\d{2}:\d{2}) (?<level>\w+) (?<msg>.+)$/', $log, $m)) {
echo "{$m['level']} at {$m['date']} {$m['time']}: {$m['msg']}\n";
}Finding All Matches and Replacing
preg_match_all() finds every non-overlapping match in a string rather than stopping at the first, returning a nested array of matches and capture groups. preg_replace() substitutes matched text with a replacement string, which can reference captured groups using $1, $2, and so on (or \1 inside single-quoted strings). For cases where the replacement logic can't be expressed as a static template — for example, transforming matched text through a function — preg_replace_callback() accepts a closure that receives the match array and returns the replacement.
Cricket analogy: Finding every boundary hit in an innings, not just the first, is like preg_match_all returning a full list, swapping 'four' for 'FOUR!' in the transcript is a direct substitution, but converting each boundary into a dynamic highlight-reel timestamp needs a callback function to compute it per hit.
$text = 'Contact: alice@example.com or bob@example.org';
preg_match_all('/[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}/', $text, $emails);
print_r($emails[0]); // ['alice@example.com', 'bob@example.org']
$masked = preg_replace_callback(
'/[\w.+-]+@([\w-]+\.[a-zA-Z]{2,})/',
fn(array $m): string => '****@' . $m[1],
$text
);
// 'Contact: ****@example.com or ****@example.org'Common Modifiers and Performance Notes
The i modifier ignores case, m makes ^ and $ match at line boundaries within a multiline string rather than only the string's start/end, s makes . match newlines too, and u treats the pattern and subject as UTF-8. Complex or poorly constructed patterns (especially those with nested quantifiers) can suffer from catastrophic backtracking, causing severe slowdowns or timeouts on certain inputs, so patterns handling untrusted input should be kept as specific and non-ambiguous as possible, and tested against pathological inputs.
Cricket analogy: A scorer noting 'ignore capitalization' in team names, treating each new scorebook line as its own entry, and reading full Unicode for foreign player names is like the i, m, and u modifiers, while an overly vague 'any player who ever scored anything' search rule could take forever on a huge database, so public submission rules must stay tightly specific.
For simple substring checks — 'does this string contain X' or 'does it start with Y' — plain string functions like str_contains() or str_starts_with() are faster and clearer than a regular expression. Reach for preg_* functions when you genuinely need pattern matching: variable structure, alternation, repetition, or capturing substructure.
Regular expressions are a poor tool for fully validating structured formats like email addresses or HTML; a regex can approximate validity but will either reject valid edge cases or accept invalid ones. For emails, PHP's built-in filter_var($email, FILTER_VALIDATE_EMAIL) is more reliable than a hand-rolled pattern, and for HTML, a proper parser (like DOMDocument) should be used instead of regex.
- PHP regex support comes from the PCRE library via preg_match, preg_match_all, preg_replace, and preg_split; patterns must use delimiters like /pattern/.
- preg_match() populates a by-reference array with the full match at index 0 and capture groups afterward; named groups use (?<name>...).
- preg_match_all() collects every match in the string, not just the first.
- preg_replace_callback() should be used instead of preg_replace() when the replacement requires computed logic rather than a static template.
- Common modifiers: i (case-insensitive), m (multiline anchors), s (dot matches newline), u (UTF-8 mode).
- Prefer built-in validators (like filter_var for email) or simple string functions over regex when a specialized tool already exists.
Practice what you learned
1. What does preg_match() return when it successfully finds one match?
2. How do you access a named capture group `(?<year>\d{4})` from a successful preg_match() call?
3. When should preg_replace_callback() be used instead of preg_replace()?
4. What does the 'i' modifier do in a PHP regex pattern like `/hello/i`?
5. Why is filter_var($email, FILTER_VALIDATE_EMAIL) often preferred over a custom regex for email validation?
Was this page helpful?
You May Also Like
String Functions and Formatting
Master PHP's core string manipulation and formatting functions, from searching and slicing to sprintf-style output and multibyte-safe operations.
Form Handling and Validation
Learn a reliable pattern for processing submitted HTML forms in PHP: reading input safely, validating and sanitizing each field, and reporting errors back to the user.
PHP Security Basics
Core security practices every PHP developer must apply — input validation, output escaping, safe database access, and secure session handling.
Working with JSON in PHP
Learn how to encode PHP data to JSON and decode JSON back into PHP values using json_encode and json_decode, plus common pitfalls and error handling.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics