Named Capture Groups in preg_match
PHP's preg_match supports PCRE named capture groups: (?P<name>...). Instead of juggling numeric match indices, your captures become a named map.
// Parse an ISO 8601 date without counting brackets
$pattern = '/^(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$/';
preg_match($pattern, '2024-03-15', $matches);
echo $matches['year']; // "2024"
echo $matches['month']; // "03"
echo $matches['day']; // "15"
// Numeric indices still work too — your choice
echo $matches[1]; // "2024"
Named groups shine in complex patterns where positional counting becomes error-prone:
// Parse a log line
$log = '[2024-03-15 14:32:01] production.ERROR: Connection refused {"host":"db1"}';
preg_match(
'/^\[(?P<date>[^\]]+)\]\s+(?P<channel>\w+)\.(?P<level>\w+):\s+(?P<message>[^{]+)/',
$log,
$m
);
echo $m['date']; // "2024-03-15 14:32:01"
echo $m['channel']; // "production"
echo $m['level']; // "ERROR"
echo trim($m['message']); // "Connection refused"
Named groups also work with preg_replace_callback, preg_match_all, and preg_replace using ${name} syntax in replacement strings.
Significance: Maintainability
Numbered capture groups are an implementation detail that leaks into your calling code. Named groups make regex patterns self-documenting — the name describes what the group captures, and your code reads the intent rather than
$m[3].