preg_match, preg_replace & More
Knowing PCRE pattern syntax is only half the picture — the other half is the family of preg_* functions that actually apply a pattern to a string. Each function answers a different question: does this string match, what parts matched, what should the string become after a substitution, or how should this string be broken apart.
preg_match(): does it match, and what did it capture?
preg_match(string $pattern, string $subject, array &$matches = null) tests whether a pattern matches anywhere in the subject string. It returns 1 if it matched, 0 if it didn't, and false if the pattern itself was malformed. When a third argument is passed by reference, it gets filled with the full match at index 0, and any parenthesized capture groups at indices 1, 2, and so on.
Capturing parts of a matched string
<?php
$log = '[2025-06-15 14:30:00] ERROR: Connection refused';
if (preg_match('/^\[(.+?)\] (\w+): (.+)$/', $log, $matches)) {
echo "Timestamp: {$matches[1]}\n";
echo "Level: {$matches[2]}\n";
echo "Message: {$matches[3]}\n";
}Timestamp: 2025-06-15 14:30:00 Level: ERROR Message: Connection refused
Named capture groups, written (?<name>...), make the resulting array self-documenting instead of relying on positional indices that break if the pattern is later reordered.
Named capture groups
<?php $log = '[2025-06-15 14:30:00] ERROR: Connection refused'; $pattern = '/^\[(?<timestamp>.+?)\] (?<level>\w+): (?<message>.+)$/'; preg_match($pattern, $log, $matches); echo $matches['level'], "\n";
ERROR
preg_match_all(): every match, not just the first
preg_match() stops at the first match. preg_match_all() finds every non-overlapping match in the subject and returns them all, as an array of arrays grouped by capture group.
Finding every match in a string
<?php
$text = 'Contact us at sales@example.com or support@example.com';
preg_match_all('/[\w.+-]+@[\w.-]+\.\w+/', $text, $matches);
print_r($matches[0]);Array
(
[0] => sales@example.com
[1] => support@example.com
)preg_replace(): pattern-based substitution
preg_replace(string $pattern, string $replacement, string $subject) substitutes every match with a replacement string. The replacement can reference captured groups using $1, $2, and so on, letting parts of the original match be reused in the output.
Reformatting a date using captured groups
<?php
$input = '2025-06-15';
$output = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3/$2/$1', $input);
echo $output, "\n";15/06/2025
preg_replace_callback(): replacement logic in code
Sometimes a substitution can't be expressed as a static string with group references — it depends on the matched text itself, like upper-casing it or looking it up somewhere. preg_replace_callback() takes a closure that receives the match array and returns the replacement string for each match.
Computing each replacement with a closure
<?php
$text = 'hello world, this is php';
$titleCased = preg_replace_callback(
'/\b\w/',
fn (array $match): string => strtoupper($match[0]),
$text
);
echo $titleCased, "\n";Hello World, This Is Php
\\b is a word-boundary anchor — it matches the position between a word character and a non-word character without consuming any characters itself, so \\b\\w matches exactly the first letter of each word.
preg_split(): breaking a string apart by pattern
explode() splits on a fixed, literal string. preg_split() splits on anything a pattern can describe, which matters when the separator isn't a single consistent character.
Splitting on one or more whitespace characters
<?php
$input = "one two\tthree\n\nfour";
$words = preg_split('/\s+/', $input);
print_r($words);Array
(
[0] => one
[1] => two
[2] => three
[3] => four
)Regardless of whether the separator in the original text was spaces, a tab, or multiple newlines, \\s+ treats it all as one delimiter and collapses it away.
A note on performance
PHP's PCRE engine compiles each unique pattern string into an internal representation before running it, and it automatically caches that compiled form — calling the same preg_* function with the same pattern string repeatedly does not recompile it from scratch each time. In practice this means there's rarely a reason to manually "optimize" by trying to reuse a compiled pattern object; the more meaningful performance lever is writing an efficient pattern in the first place.
preg_match()reports whether a pattern matched and captures the first match into a$matchesarray.preg_match_all()finds every match in the subject, not just the first.preg_replace()substitutes matches with a string that can reference capture groups via$1,$2, etc.preg_replace_callback()computes each replacement with a closure instead of a static string.preg_split()breaks a string apart wherever a pattern matches.Compiled patterns are cached automatically by PHP — manual caching is not needed.