preg_grep

Returns the array elements that match a regular expression, keeping their original keys.

Signature
preg_grep(string $pattern, array $array, int $flags = 0): array|false
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$patternstringThe pattern to test each element against, including delimiters.
$arrayarrayThe input array. Its values are tested as strings.
$flagsoptionalint= 00, or PREG_GREP_INVERT to return the elements that do not match.

Return value

array|falseAn array of the elements that matched, indexed with the keys they had in the input array. Returns false on failure.

Errors

Emits an E_WARNING and returns false when the pattern fails to compile. No ValueError is thrown for an invalid flags value: php_pcre_grep_impl only does `invert = flags & PREG_GREP_INVERT`, so any other bits are silently ignored. Verified on PHP 8.3: preg_grep('/a/', ['a'], 99) returns an array with no exception.

preg_grep() is the regex version of array_filter(): it runs one pattern against every value in an array and hands back the ones that matched, keys intact. Pass PREG_GREP_INVERT and you get the complement instead.

When to reach for it

Reach for it whenever you would otherwise write array_filter($a, fn($v) => preg_match($p, $v)) — it is shorter, does the same thing, and avoids a userland call per element. Typical jobs: pick out the log lines that mention a request ID, keep only the filenames with an image extension, or strip every key-looking string out of a config dump with the invert flag.

What trips people up

Two things. First, it filters on values, not keys; there is no built-in way to grep the keys, so filter array_keys($a) and intersect if that is what you need. Second, the result keeps the original numeric keys, so $result[0] may not exist and json_encode() will emit an object. Non-string values such as integers are coerced to strings before matching; objects without __toString() will raise an error.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Keep only the uploaded filenames whose extension is on an allow-list
  • Pull every log line that contains a trace ID out of an array of lines
  • Drop all comment and blank lines from a config file read with file()

Frequently asked questions

How do I filter an array by a regular expression in PHP?

Call preg_grep() with the pattern and the array; it returns the matching elements with their keys preserved. Add PREG_GREP_INVERT as the third argument to get the non-matching ones instead.

What is the difference between preg_grep and array_filter?

preg_grep tests each value against one regex, while array_filter runs an arbitrary callback. preg_grep is faster for a plain pattern test because it does not call back into PHP for every element.

Does preg_grep search array keys?

No, it only tests values. To filter by key, run preg_grep on array_keys() and combine the result with array_intersect_key() and array_flip().

More examples

Stripping comments and blank lines

The pattern matches lines that are blank or start with a hash; PREG_GREP_INVERT flips it so those lines are removed. array_values() renumbers the gaps left by keys 0, 2 and 4.

Example · php
<?php
$config = ['# database', 'host=localhost', '', 'port=5432', '  # end'];

$clean = preg_grep('/^\s*(#|$)/', $config, PREG_GREP_INVERT);

print_r(array_values($clean));

Grepping the keys instead of the values

preg_grep only looks at values, so the keys are grepped separately and then intersected back. The output keeps user_id and user_name and drops created_at.

Example · php
<?php
$row = ['user_id' => 3, 'user_name' => 'ada', 'created_at' => '2026-08-30'];

$userKeys = preg_grep('/^user_/', array_keys($row));
$subset   = array_intersect_key($row, array_flip($userKeys));

print_r($subset);

Numbers are matched as strings

Values are cast to string before matching, so the integer 10 and the string '20' both match. 3.5 becomes '3.5' and fails on the dot, and 'x9' fails on the anchor — both are dropped.

Example · php
<?php
$mixed = [10, '20', 3.5, 'x9'];

print_r(preg_grep('/^\d+$/', $mixed));

Discussion

  • Be the first to comment on this lesson.