preg_match_all()
In PHP, regular expressions are an essential tool for manipulating and searching strings. The preg_match_all() function is one of the many functions that PHP
Introduction
In PHP, regular expressions are essential for searching and manipulating strings. While preg_match() stops at the first match, preg_match_all() keeps scanning and returns every occurrence of a pattern in a string. Use it whenever you need to extract all phone numbers, all tags, all words, or any repeating structure from text.
This article explains the syntax, the all-important $flags argument that controls how results are laid out, and several practical examples.
Syntax
preg_match_all(
string $pattern,
string $subject,
array &$matches = null,
int $flags = PREG_PATTERN_ORDER,
int $offset = 0
): int|false$pattern— the regular expression, delimited by/.../(or any matching delimiters).$subject— the string to search.$matches— an output array (passed by reference) filled with all matches found.$flags— optional. Controls how$matchesis structured (see below).$offset— optional. Byte offset in$subjectat which to start searching.
It returns the number of full pattern matches (which may be 0), or false if the pattern is invalid.
A simple match
The most basic use is to collect every substring that matches a pattern. Here we pull all numbers out of a sentence:
<?php
$subject = 'Room 12, floor 3, building 7';
$count = preg_match_all('/\d+/', $subject, $matches);
echo "Found $count numbers\n";
print_r($matches[0]);Output:
Found 3 numbers
Array
(
[0] => 12
[1] => 3
[2] => 7
)When the pattern has no capturing groups, $matches[0] holds the list of full matches.
Choosing a flag: PREG_PATTERN_ORDER vs PREG_SET_ORDER
The $flags argument decides how matches and capturing groups are organized. The two main flags are mutually exclusive:
PREG_PATTERN_ORDER(the default) —$matches[0]is all full matches,$matches[1]is all captures of group 1,$matches[2]is all captures of group 2, and so on. Think "column by column."PREG_SET_ORDER—$matches[0]is the first complete match (full match + its groups),$matches[1]is the second, and so on. Think "row by row."
You can also add PREG_OFFSET_CAPTURE to record the byte offset of each match alongside its text.
PREG_SET_ORDER (group results by occurrence)
This layout is the easiest to loop over when each match has several capturing groups:
Output:
Name: Alice, Age: 25
Name: Bob, Age: 30With PREG_SET_ORDER, each $match is one occurrence: $match[0] is the full match, $match[1] is the first group (name), $match[2] is the second group (age).
PREG_PATTERN_ORDER (group results by pattern)
The same pattern with the default flag returns the groups as parallel arrays:
<?php
$pattern = '/([A-Z][a-z]+) (\d+)/';
$subject = 'Alice 25 Bob 30';
preg_match_all($pattern, $subject, $matches, PREG_PATTERN_ORDER);
print_r($matches[1]); // all names
print_r($matches[2]); // all agesOutput:
Array
(
[0] => Alice
[1] => Bob
)
Array
(
[0] => 25
[1] => 30
)Named capturing groups
Naming groups with (?<name>...) makes the result self-documenting — the names become array keys (alongside the numeric indexes):
<?php
$pattern = '/(?<name>[A-Z][a-z]+) (?<age>\d+)/';
$subject = 'Alice 25 Bob 30';
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
echo "{$match['name']} is {$match['age']}\n";
}Output:
Alice is 25
Bob is 30Common gotchas
- Check the return value, not the array. A pattern can match zero times and still succeed;
preg_match_all()returns0, whilefalsemeans the regex itself was invalid. Use=== falseto detect errors. Seepreg_last_error()for the specific failure reason. $matchesis overwritten. Each call replaces the previous contents of the output array.- Pick the right flag for your loop. Use
PREG_SET_ORDERwhen you want one row per match; use the defaultPREG_PATTERN_ORDERwhen you want one column per group. - Escape special characters in dynamic patterns with
preg_quote()when the pattern comes from user input.
Conclusion
preg_match_all() returns every match of a pattern in a string, making it the go-to function for extracting repeating data. The key to using it well is understanding the $flags argument: PREG_SET_ORDER groups results by occurrence, while the default PREG_PATTERN_ORDER groups them by capturing group.
For related tools, see preg_match() for a single match, preg_replace() for find-and-replace, and preg_split() for splitting strings by a pattern.