PHP Array Filtering
last modified October 22, 2026
PHP offers several tools for filtering arrays and objects, such as
array_filter, array_map, array_reduce,
and the filter_var family of functions. This tutorial explores
them with practical examples.
Predicates, the functions that decide whether an element is kept, are covered in more detail in the PHP predicates article.
Basic array filtering
The array_filter function passes each element to a callback and
returns a new array with the elements for which the callback returns
true.
<?php $numbers = [1, 2, 3, 4, 5, 6]; $evenNumbers = array_filter($numbers, fn($num) => $num % 2 === 0); print_r($evenNumbers); print_r(array_values($evenNumbers));
The arrow function keeps the even numbers. The original array is not changed.
Note that array_filter preserves the keys: the result has the keys
1, 3 and 5, not 0, 1 and 2. If a list with consecutive keys is needed, for
example before encoding it to JSON, wrap the result in
array_values.
$ php basic_filter.php
Array
(
[1] => 2
[3] => 4
[5] => 6
)
Array
(
[0] => 2
[1] => 4
[2] => 6
)
Filtering without a callback
Without a callback, array_filter removes all values that are
falsy.
<?php $values = ['sky', '', 0, 'blue', null, '0', false, 12, []]; var_export(array_filter($values)); echo "\n"; $withZeros = array_filter($values, fn($v) => $v !== null && $v !== ''); var_export($withZeros); echo "\n";
The empty string, 0, null, the string
'0', false and the empty array are all removed. This
is often too aggressive; the second call removes only null and
empty strings and keeps legitimate zeros. We use var_export because
print_r shows false as an empty string.
$ php no_callback.php array ( 0 => 'sky', 3 => 'blue', 7 => 12, ) array ( 0 => 'sky', 2 => 0, 3 => 'blue', 5 => '0', 6 => false, 7 => 12, 8 => array ( ), )
Filtering with keys
With the ARRAY_FILTER_USE_BOTH flag, the callback receives both the
value and the key.
<?php
$data = ["a" => 1, "b" => 2, "c" => 3, "d" => 4];
$filtered = array_filter($data, fn($v, $k) => $k === "b" || $v > 2,
ARRAY_FILTER_USE_BOTH);
print_r($filtered);
The callback keeps an element if its key is "b" or its value is
greater than 2. Element "b" => 2 is kept because of its key,
"c" and "d" because of their values. The
ARRAY_FILTER_USE_KEY flag passes only the key.
$ php filter_with_keys.php
Array
(
[b] => 2
[c] => 3
[d] => 4
)
Keeping allowed keys
When only a known set of keys is wanted, array_intersect_key is
simpler than a callback.
<?php
$input = [
'name' => 'Jane',
'email' => 'jane@example.com',
'is_admin' => true,
'age' => '31',
];
$allowed = ['name', 'email', 'age'];
$safe = array_intersect_key($input, array_flip($allowed));
print_r($safe);
The array_flip function turns the list of allowed keys into an
array with those keys, and array_intersect_key keeps only the
matching entries of the input. This is a common way to drop unexpected fields,
such as is_admin, from user input.
$ php allowed_keys.php
Array
(
[name] => Jane
[email] => jane@example.com
[age] => 31
)
Filtering objects
Callbacks can test object properties.
<?php
class Product
{
public function __construct(
public string $name,
public float $price,
) {}
}
$products = [
new Product("Laptop", 1000),
new Product("Phone", 500),
new Product("Tablet", 300),
];
$affordable = array_filter($products, fn(Product $p) => $p->price < 800);
foreach ($affordable as $i => $product) {
echo "$i: $product->name ($product->price)\n";
}
The callback keeps products cheaper than 800. The laptop is removed, and the phone and tablet keep their original indices 1 and 2.
$ php filter_objects.php 1: Phone (500) 2: Tablet (300)
Filtering associative arrays
Rows from a database or an API are usually associative arrays.
<?php
$users = [
["name" => "John", "age" => 25],
["name" => "Jane", "age" => 30],
["name" => "Doe", "age" => 17],
];
$adults = array_filter($users, fn($user) => $user["age"] >= 18);
echo implode(', ', array_column($adults, 'name')), "\n";
The callback keeps users who are 18 or older. The array_column
function then extracts their names.
$ php filter_associative.php John, Jane
Filtering by multiple criteria
Conditions can be combined with logical operators.
<?php
class Item
{
public function __construct(
public string $name,
public float $price,
public int $stock,
) {}
}
$items = [
new Item("Laptop", 1000, 5),
new Item("Phone", 500, 10),
new Item("Tablet", 300, 0),
new Item("Mouse", 25, 40),
];
$available = array_filter($items, fn(Item $i) => $i->price < 800 && $i->stock > 0);
foreach ($available as $item) {
echo "$item->name: $item->price, $item->stock in stock\n";
}
An item is kept when it costs less than 800 and is in stock. The laptop fails the price check and the tablet the stock check.
$ php filter_multi_criteria.php Phone: 500, 10 in stock Mouse: 25, 40 in stock
Combining array_filter and array_map
Filtering and transformation are often done in sequence.
<?php $numbers = [1, 2, 3, 4, 5, 6]; $evens = array_filter($numbers, fn($num) => $num % 2 === 0); $doubled = array_map(fn($num) => $num * 2, $evens); print_r($doubled); $sum = array_sum($doubled); echo "Sum: $sum\n";
The even numbers are selected first and then doubled. Filtering first means
that the transformation runs on fewer elements. The array_map
function preserves the keys of a single input array, so the result still has
the keys 1, 3 and 5.
$ php combine_filter_map.php
Array
(
[1] => 4
[3] => 8
[5] => 12
)
Sum: 24
Partitioning with array_reduce
array_reduce can split an array into several groups in one pass.
<?php
$users = [
["name" => "John", "age" => 25],
["name" => "Jane", "age" => 30],
["name" => "Doe", "age" => 17],
["name" => "Anna", "age" => 15],
];
$groups = array_reduce($users, function (array $carry, array $user) {
$key = $user['age'] >= 18 ? 'adults' : 'minors';
$carry[$key][] = $user['name'];
return $carry;
}, ['adults' => [], 'minors' => []]);
print_r($groups);
The accumulator starts with two empty groups. The callback puts each user's name into one of them and returns the updated accumulator.
$ php reduce_group.php
Array
(
[adults] => Array
(
[0] => John
[1] => Jane
)
[minors] => Array
(
[0] => Doe
[1] => Anna
)
)
Filtering unique values
The array_unique function removes duplicate values.
<?php
$values = [1, 2, 2, 3, 3, 4];
$uniqueSquares = array_unique(array_map(fn($v) => $v * $v, $values));
print_r($uniqueSquares);
$emails = ['Jane@Example.com', 'john@example.com', 'jane@example.com'];
$unique = array_values(array_unique(array_map('strtolower', $emails)));
print_r($unique);
array_unique keeps the first occurrence of each value together
with its key, so the squared values keep the keys 0, 1, 3 and 5. In the second
part, the email addresses are normalized to lowercase before deduplication, and
array_values renumbers the result.
$ php filter_unique.php
Array
(
[0] => 1
[1] => 4
[3] => 9
[5] => 16
)
Array
(
[0] => jane@example.com
[1] => john@example.com
)
Filtering nested arrays
To filter the values of a nested array, we can flatten it first.
<?php
function flatten(array $data): array
{
$result = [];
array_walk_recursive($data, function ($value) use (&$result) {
$result[] = $value;
});
return $result;
}
$data = [1, [2, 3], [4, [5, 6]]];
$evens = array_filter(flatten($data), fn($n) => $n % 2 === 0);
echo implode(' ', $evens), "\n";
The array_walk_recursive function visits every leaf value of the
nested array. The closure captures $result by reference and
collects the values. The flat list is then filtered with
array_filter.
$ php filter_nested.php 2 4 6
Recursive filtering
Sometimes the structure must be kept and only the unwanted leaves removed.
<?php
function filterRecursive(array $data, callable $keep): array
{
$result = [];
foreach ($data as $key => $value) {
if (is_array($value)) {
$value = filterRecursive($value, $keep);
if ($value !== []) {
$result[$key] = $value;
}
} elseif ($keep($value)) {
$result[$key] = $value;
}
}
return $result;
}
$config = [
'db' => ['host' => 'localhost', 'password' => null, 'port' => 5432],
'cache' => ['driver' => null],
'debug' => false,
'name' => 'app',
];
var_export(filterRecursive($config, fn($v) => $v !== null));
echo "\n";
The filterRecursive function descends into nested arrays and
removes values for which the callback returns false. Arrays that
become empty, like cache, are removed as well. A named function is
used because an arrow function cannot easily call itself.
$ php filter_recursive.php
array (
'db' =>
array (
'host' => 'localhost',
'port' => 5432,
),
'debug' => false,
'name' => 'app',
)
Validating data with filter_var_array
The filter extension validates and converts input data, such as values from a form.
<?php
$input = [
'age' => '31',
'email' => 'jane@example.com',
'homepage' => 'not a url',
'newsletter' => 'yes',
];
$rules = [
'age' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 130]],
'email' => FILTER_VALIDATE_EMAIL,
'homepage' => FILTER_VALIDATE_URL,
'newsletter' => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
];
var_dump(filter_var_array($input, $rules));
Each key gets its own filter. FILTER_VALIDATE_INT converts the
string to an integer and checks the range, FILTER_VALIDATE_EMAIL
and FILTER_VALIDATE_URL check the format, and
FILTER_VALIDATE_BOOL accepts values like yes,
on or 1. A value that fails validation becomes
false, or null with the
FILTER_NULL_ON_FAILURE flag.
$ php filter_var.php
array(4) {
["age"]=>
int(31)
["email"]=>
string(16) "jane@example.com"
["homepage"]=>
bool(false)
["newsletter"]=>
bool(true)
}
Lazy filtering with generators
array_filter needs the whole array in memory. A generator filters
items one by one, which works for large or even infinite sequences.
<?php
function filterLazy(iterable $items, callable $keep): Generator
{
foreach ($items as $key => $item) {
if ($keep($item)) {
yield $key => $item;
}
}
}
function numbers(): Generator
{
for ($i = 1; ; $i++) {
echo "producing $i\n";
yield $i;
}
}
foreach (filterLazy(numbers(), fn($n) => $n % 3 === 0) as $n) {
echo "got $n\n";
if ($n >= 6) {
break;
}
}
The numbers generator never ends, yet the program finishes, because
values are produced only on demand. The output shows that producing and
filtering are interleaved.
$ php generator.php producing 1 producing 2 producing 3 got 3 producing 4 producing 5 producing 6 got 6
Filtering users by age
This example filters user objects by age, calculated from their date of birth.
<?php
class User
{
public function __construct(
public string $firstName,
public string $lastName,
public string $city,
public DateTimeImmutable $dateOfBirth,
) {}
public function ageOn(DateTimeImmutable $date): int
{
return $this->dateOfBirth->diff($date)->y;
}
}
$users = [
new User("John", "Doe", "New York", new DateTimeImmutable("2000-05-15")),
new User("Jane", "Smith", "Los Angeles", new DateTimeImmutable("1995-08-22")),
new User("Alice", "Johnson", "Chicago", new DateTimeImmutable("2010-03-10")),
new User("Bob", "Brown", "Houston", new DateTimeImmutable("1998-11-30")),
new User("Emma", "Davis", "Seattle", new DateTimeImmutable("2008-10-23")),
new User("Mike", "Wilson", "Boston", new DateTimeImmutable("1990-01-25")),
new User("Sarah", "Taylor", "Miami", new DateTimeImmutable("2008-10-22")),
];
$today = new DateTimeImmutable("2026-10-22");
$adults = array_filter($users, fn(User $u) => $u->ageOn($today) >= 18);
foreach ($adults as $user) {
printf("%-6s %-8s %-12s %d\n", $user->firstName, $user->lastName,
$user->city, $user->ageOn($today));
}
The ageOn method computes the age in whole years with
diff. A fixed date is used instead of the current one, so the
result is reproducible: Sarah turns 18 on this day and is included, while Emma,
who is one day younger, is not.
$ php filter_users_by_age.php John Doe New York 26 Jane Smith Los Angeles 31 Bob Brown Houston 27 Mike Wilson Boston 36 Sarah Taylor Miami 18
Best practices for array filtering
- Remember the keys:
array_filterandarray_uniquepreserve keys; usearray_valueswhen a list is needed. - Be explicit: filtering without a callback also removes
0and'0'; pass a callback when such values are valid. - Filter early: filter before mapping or sorting to reduce the amount of work.
- Validate input: use
filter_varandfilter_var_arrayfor user data rather than hand-written checks.
Source
PHP array_filter - Documentation
In this article, we have covered filtering arrays and objects in PHP with
array_filter, array_reduce, recursive and lazy
filtering, and the filter extension.
Author
List all PHP tutorials.