Searching, Filtering & Mapping
Once you are comfortable with plain loops, three functions - array_filter(), array_map(), and array_reduce() - let you express common data-processing steps in a single expression instead of a multi-line loop. They are not strictly necessary (a foreach can always do the same job), but they read declaratively: filter says "keep only these," map says "transform every one of these," and reduce says "combine all of these into one thing." Chaining them together is how PHP developers commonly build small data pipelines.
array_filter(): keeping what matches
array_filter() returns a new array containing only the elements for which a callback returns something truthy. Called without a callback, it simply drops every "falsy" value - false, 0, "0", null, "", and empty arrays.
Filtering with and without a callback
<?php $mixed = [0, 1, "", "hello", null, false, 42]; print_r(array_filter($mixed)); // drops all falsy values $numbers = [1, 2, 3, 4, 5, 6, 7, 8]; $evens = array_filter($numbers, fn ($n) => $n % 2 === 0); print_r($evens);
Array
(
[1] => 1
[3] => hello
[6] => 42
)
Array
(
[1] => 2
[3] => 4
[5] => 6
[7] => 8
)Filtering by key or by both key and value
By default the callback receives only the value. Passing the ARRAY_FILTER_USE_KEY flag switches the callback to receive the key instead, and ARRAY_FILTER_USE_BOTH passes both value and key.
Filtering on keys and on both key and value
<?php
$scores = ["alice_score" => 91, "bob_note" => "n/a", "carol_score" => 85];
$scoreFields = array_filter(
$scores,
fn ($key) => str_ends_with($key, "_score"),
ARRAY_FILTER_USE_KEY
);
print_r($scoreFields);
$highScorers = array_filter(
$scores,
fn ($value, $key) => str_ends_with($key, "_score") && $value >= 90,
ARRAY_FILTER_USE_BOTH
);
print_r($highScorers);Array
(
[alice_score] => 91
[carol_score] => 85
)
Array
(
[alice_score] => 91
)array_map(): transforming every element
array_map() applies a callback to every element and returns a new array of the results, in the same order, with keys preserved for a single input array. It can also accept multiple arrays at once, in which case the callback receives one element from each array per call - handy for combining two related lists position by position.
Mapping one array, then mapping two in parallel
<?php
$prices = [10, 20, 30];
$withTax = array_map(fn ($price) => round($price * 1.08, 2), $prices);
print_r($withTax);
$names = ["Kai", "Uma"];
$ages = [28, 35];
$combined = array_map(fn ($name, $age) => "{$name} ({$age})", $names, $ages);
print_r($combined);Array
(
[0] => 10.8
[1] => 21.6
[2] => 32.4
)
Array
(
[0] => Kai (28)
[1] => Uma (35)
)array_reduce(): combining into one value
array_reduce() walks the array and repeatedly applies a callback that combines an "accumulator" with the next element, eventually producing a single result - a total, a concatenated string, or even a newly built array. The optional third argument sets the accumulator's starting value.
Summing and building a lookup table with reduce
<?php
$prices = [10, 20, 30];
$total = array_reduce($prices, fn ($carry, $price) => $carry + $price, 0);
echo $total; // 60
echo "\n";
$users = [
["id" => 1, "name" => "Ravi"],
["id" => 2, "name" => "Sam"],
];
$byId = array_reduce($users, function ($carry, $user) {
$carry[$user["id"]] = $user["name"];
return $carry;
}, []);
print_r($byId);60
Array
(
[1] => Ravi
[2] => Sam
)Composing a small pipeline
The real payoff comes from chaining these functions: filter down to the rows you care about, map them into the shape you need, then reduce to a summary value. This reads as a sequence of clear steps instead of one dense loop with several responsibilities mixed together.
Filter, then map, then reduce
<?php
$orders = [
["id" => 1, "status" => "paid", "total" => 42.50],
["id" => 2, "status" => "pending", "total" => 19.00],
["id" => 3, "status" => "paid", "total" => 75.20],
];
$paidTotals = array_map(
fn ($order) => $order["total"],
array_filter($orders, fn ($order) => $order["status"] === "paid")
);
$revenue = array_reduce($paidTotals, fn ($carry, $total) => $carry + $total, 0);
echo "Paid revenue: \${$revenue}"; // 117.7Paid revenue: $117.7
array_filter()andarray_map()never mutate the array you pass in - both return a brand-new array.Arrow functions (
fn ($x) => ...) are usually cleaner thanfunction ($x) { return ...; }for these short, single-expression callbacks.array_map(null, $a, $b)(withnullas the callback) zips two arrays together into pairs without transforming anything.For very large datasets, chaining several of these functions builds several intermediate arrays in memory - a plain
foreachcan be more memory-efficient when that matters.