array_map / array_filter / array_reduce

Yo Yogesh.M Updated 01 Nov 2026
8 min read ·Lesson 210 of 219

array_map(), array_filter(), and array_reduce() are the three core functions for processing arrays without writing loops by hand. Each one expresses a common pattern:

FunctionPatternInput → Output
array_map()Transform every elementN elements → N elements
array_filter()Select elements that pass a testN elements → 0…N elements
array_reduce()Combine all elements into one valueN elements → 1 value

Each takes a callback — a function you provide (often an arrow function) that describes what to do with each element. The loop itself is handled by PHP.

$withGst  = array_map(fn($price) => $price * 1.18, $prices);   // transform
$cheap    = array_filter($prices, fn($price) => $price < 500); // select
$total    = array_reduce($prices, fn($sum, $price) => $sum + $price, 0); // combine

Why Use Them

  • Intent is explicit: "map", "filter", and "reduce" describe what happens, while a foreach loop must be read line by line to understand its purpose.
  • No temporary variables or accidental mutations: each function returns a new value and leaves the input array unchanged.
  • Composable: the result of one can be passed directly to the next, forming a data pipeline.

array_map() — Transform Every Element

Syntax

array_map(?callable $callback, array $array, array ...$arrays): array

Example

<?php
$prices = [100, 250, 499];
$withGst = array_map(fn(float $price): float => round($price * 1.18, 2), $prices);
$labels = array_map(fn(float $price): string => '₹' . number_format($price, 2), $withGst);
echo implode(', ', $labels) . "\n";
echo implode(', ', $prices) . "\n";

Output

₹118.00, ₹295.00, ₹588.82
100, 250, 499

The callback receives each value and returns the new value. The result has the same number of elements, and the original $prices is unchanged.

Keys Are Preserved With One Array

<?php
$prices = ['Pen' => 20, 'Lamp' => 1299];
print_r(array_map(fn(int $price): int => $price * 2, $prices));

Output

Array
(
    [Pen] => 40
    [Lamp] => 2598
)

With a single input array, array_map() keeps the keys. With several arrays, the result is re-indexed.

Accessing Keys in the Callback

The callback receives only values. To use the keys too, pass array_keys() as a second array:

<?php
$prices = ['Pen' => 20, 'Lamp' => 1299];
$lines = array_map(
    fn(string $item, int $price): string => "$item: ₹$price",
    array_keys($prices),
    $prices
);
print_r($lines);

Output

Array
(
    [0] => Pen: ₹20
    [1] => Lamp: ₹1299
)

Combining Several Arrays

When given multiple arrays, the callback receives one element from each, position by position:

<?php
$names = ['Asha', 'Bala', 'Charu'];
$scores = [88, 72, 95];
print_r(array_map(fn(string $name, int $score): string => "$name scored $score", $names, $scores));
echo json_encode(array_map(null, [1, 2], ['a', 'b'])) . "\n";

Output

Array
(
    [0] => Asha scored 88
    [1] => Bala scored 72
    [2] => Charu scored 95
)
[[1,"a"],[2,"b"]]

Passing null as the callback "zips" the arrays into pairs. If the arrays differ in length, shorter ones are padded with null.


array_filter() — Keep Matching Elements

Syntax

array_filter(array $array, ?callable $callback = null, int $mode = 0): array

Example

<?php
$scores = ['Asha' => 88, 'Bala' => 34, 'Charu' => 95, 'Dev' => 39];
$passed = array_filter($scores, fn(int $score): bool => $score >= 40);
print_r($passed);

Output

Array
(
    [Asha] => 88
    [Charu] => 95
)

The callback returns true to keep an element. Keys are preserved — wrap the result in array_values() if you need a list with continuous indexes (for example, before json_encode()).

Filtering by Key or by Key and Value

<?php
$env = ['DB_HOST' => 'localhost', 'DB_PORT' => '3306', 'MAIL_DRIVER' => 'smtp', 'DB_NAME' => 'shop'];
$dbSettings = array_filter(
    $env,
    fn(string $key): bool => str_starts_with($key, 'DB_'),
    ARRAY_FILTER_USE_KEY
);
$stock = ['Pen' => 100, 'Lamp' => 0, 'Bag' => 4, 'Mug' => 12];
$available = array_filter(
    $stock,
    fn(int $qty, string $item): bool => $qty > 0 && $item !== 'Mug',
    ARRAY_FILTER_USE_BOTH
);
echo implode(', ', array_keys($dbSettings)) . "\n";
echo implode(', ', array_keys($available)) . "\n";

Output

DB_HOST, DB_PORT, DB_NAME
Pen, Bag
ModeCallback Receives
0 (default)The value
ARRAY_FILTER_USE_KEYThe key
ARRAY_FILTER_USE_BOTHThe value and the key

Without a Callback

Without a callback, array_filter() removes all falsy values — false, null, 0, 0.0, '', '0', and []. This is convenient for removing empty entries but also removes valid zeros. Pass an explicit callback for user data (see Remove Array Items).


array_reduce() — Combine Into One Value

Syntax

array_reduce(array $array, callable $callback, mixed $initial = null): mixed

The callback receives an accumulator (often called $carry) and the current element. Whatever it returns becomes the accumulator for the next element. After the last element, the accumulator is the result.

Example: Sum

<?php
$cart = [499, 1299, 89];
$total = array_reduce($cart, fn(int $carry, int $price): int => $carry + $price, 0);
echo $total . "\n";

Output

1887

Step by Step

Step$carry (before)$priceReturned
10 (initial)499499
249912991798
31798891887

For a simple sum, array_sum() is shorter. array_reduce() is valuable when the combination is more complex.

Example: Finding the Most Expensive Product

<?php
$products = [
    ['name' => 'Gel Pen', 'price' => 20],
    ['name' => 'Desk Lamp', 'price' => 1299],
    ['name' => 'Backpack', 'price' => 899],
];
$mostExpensive = array_reduce(
    $products,
    fn(?array $carry, array $product): array =>
        $carry === null || $product['price'] > $carry['price'] ? $product : $carry
);
echo $mostExpensive['name'] . "\n";

Output

Desk Lamp

With no initial value, the accumulator starts as null; the first product then becomes the "best so far", and each later product replaces it only if it is more expensive.

Example: Counting by Group

<?php
$statuses = ['paid', 'pending', 'paid', 'cancelled', 'paid'];
$counts = array_reduce($statuses, function (array $carry, string $status): array {
    $carry[$status] = ($carry[$status] ?? 0) + 1;
    return $carry;
}, []);
print_r($counts);

Output

Array
(
    [paid] => 3
    [pending] => 1
    [cancelled] => 1
)

The accumulator can be an array, so array_reduce() can build any structure.

Always Provide an Initial Value When Possible

<?php
var_dump(array_reduce([], fn($carry, $n) => $carry + $n));
var_dump(array_reduce([], fn($carry, $n) => $carry + $n, 0));

Output

NULL
int(0)

For an empty array, the callback never runs and the initial value is returned. Without an explicit initial value, that is null — which can cause type errors later. Pass a sensible starting value (0, '', []).


Combining Them: A Data Pipeline

<?php
$orders = [
    ['id' => 1, 'customer' => 'Asha', 'total' => 1250, 'status' => 'paid'],
    ['id' => 2, 'customer' => 'Bala', 'total' => 640, 'status' => 'pending'],
    ['id' => 3, 'customer' => 'Charu', 'total' => 3200, 'status' => 'paid'],
    ['id' => 4, 'customer' => 'Dev', 'total' => 980, 'status' => 'paid'],
];
$paidOrders = array_filter($orders, fn(array $o): bool => $o['status'] === 'paid');
$totals = array_map(fn(array $o): int => $o['total'], $paidOrders);
$revenue = array_reduce($totals, fn(int $sum, int $total): int => $sum + $total, 0);
$largest = array_reduce(
    $paidOrders,
    fn(?array $best, array $o): array => $best === null || $o['total'] > $best['total'] ? $o : $best
);
echo "Paid orders: " . count($paidOrders) . "\n";
echo "Revenue: ₹" . number_format($revenue) . "\n";
echo "Average order: ₹" . number_format($revenue / count($paidOrders)) . "\n";
echo "Largest: {$largest['customer']} (₹" . number_format($largest['total']) . ")\n";

Output

Paid orders: 3
Revenue: ₹5,430
Average order: ₹1,810
Largest: Charu (₹3,200)

Step-by-Step Explanation

  1. Filter: keep only paid orders (orders 1, 3, and 4).
  2. Map: turn each order into its total.
  3. Reduce: add the totals: 1250 + 3200 + 980 = 5430.
  4. Reduce again: find the order with the highest total. Each step has one responsibility and produces a new array, so intermediate results can be inspected or reused. (array_sum(array_column($paidOrders, 'total')) would compute the revenue more directly; the explicit steps illustrate the pattern.)

With the Pipe Operator (PHP 8.5+)

$revenue = $orders
    |> (fn(array $o) => array_filter($o, fn($x) => $x['status'] === 'paid'))
    |> (fn(array $o) => array_column($o, 'total'))
    |> array_sum(...);

The pipe operator passes each result into the next step, reading top to bottom.


When to Use a foreach Loop Instead

Use the functions when…Use foreach when…
Each step is a short, pure transformationThe body performs several actions or side effects (saving, sending, logging)
You need a new array and want to keep the originalYou must stop early (break) — or use array_find() in PHP 8.4+
The logic fits in a small callbackThe logic needs many variables or complex conditions

Both styles are good PHP. Choose the one that makes the code easiest to read.


Common Mistakes

Wrong Argument Order

array_map($callback, $array) takes the callback first; array_filter($array, $callback) and array_reduce($array, $callback) take the array first. Mixing them up causes a TypeError.

Expecting array_filter() to Re-index

Effect: Gaps in keys and JSON objects instead of arrays. Fix: array_values(array_filter(...)).

Forgetting the Initial Value in array_reduce()

Effect: null result for empty arrays. Fix: Pass an initial value matching the expected result type.

Expecting Keys in the array_map() Callback

Effect: Only values are passed. Fix: Pass array_keys($array) as an additional array, or use foreach.

Side Effects Inside Callbacks

Effect: Hidden actions (database writes, emails) inside a "transformation" make code hard to understand. Fix: Keep callbacks pure; perform side effects in a clear loop.


Best Practices

  • Use array_map() to transform, array_filter() to select, and array_reduce() to combine.
  • Write short callbacks as typed arrow functions.
  • Re-index filtered lists with array_values() when order and continuity matter.
  • Always give array_reduce() an initial value.
  • Prefer specialized functions (array_sum(), array_column(), array_find()) when they express the task directly. Official reference: https://www.php.net/manual/en/function.array-map.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings Function Arguments PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer PHP Form Handling PHP XML Parsers PDO Transactions PDO Error Handling PHP XML Parsers PHP SimpleXML Parser PHP SimpleXML - Get PHP XML Expat Parser PHP DOM Parser PHP XMLReader PHP XMLWriter AJAX Intro PHP Class Constants Encryption with Sodium Recursive Functions Variable Functions Anonymous Functions Closures Arrow Functions First-class Callable Syntax PHP Arrays Indexed Arrays Associative Arrays Create Arrays Variables Scope Static Variables Variable Variables PHP Echo / Print PHP printf / sprintf PHP Data Types PHP Booleans PHP NULL PHP Strings String Functions array_map / array_filter / array_reduce Array Functions What Are Superglobals? $GLOBALS What Is `$_SERVER` ? $_REQUEST $_POST $_GET $_FILES $_COOKIE
Ask about this post
AI Ask about this post

Ask questions about array_map / array_filter / array_reduce and get answers drawn from it.

Signed-in readers only.