PHPSearching, Filtering & Mapping

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
<?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
)
array_filter() keeps the original keys
Notice the keys in the output above are not renumbered - `array_filter()` preserves whatever keys the surviving elements had. If you need a clean, sequential array afterward (for example, before returning it as a JSON list), wrap the call in `array_values()`.
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
<?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
<?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
<?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
<?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.7
Paid revenue: $117.7
  • array_filter() and array_map() never mutate the array you pass in - both return a brand-new array.

  • Arrow functions (fn ($x) => ...) are usually cleaner than function ($x) { return ...; } for these short, single-expression callbacks.

  • array_map(null, $a, $b) (with null as 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 foreach can be more memory-efficient when that matters.

Order of filter and map matters for performance
Filtering before mapping (as in the pipeline example) means the transformation only runs on the rows you actually kept. Mapping first and filtering second works too, but wastes effort transforming rows you are about to discard.
Tip
Reach for `array_filter()` + `array_map()` + `array_reduce()` when the transformation is a straightforward, side-effect-free computation. If you find yourself needing early exits, complex branching, or side effects like logging, a plain `foreach` will usually be more readable than forcing it into a functional chain.