Arrays7 min readExamples run on PHP 8.5.10

array_reduce()

Learn how array_reduce() folds an array into one value with a callback, how the initial value works, and which mistakes to avoid.

Signature

array_reduce(array $array, callable $callback, mixed $initial = null): mixed
Available since PHP 4.0.57.48.08.18.28.38.48.5All versions →

Purpose

array_reduce() walks through an array from the first element to the last and combines the elements into one result. That result can be a number, a string, an array, or any other value. The function keeps a running value, called the carry, and passes it with each element to your callback. Whatever the callback returns becomes the carry for the next step. Typical uses are totals, products, counts, longest-string searches, and building a new structure such as a grouped array.

Signature

The callback has this shape:

function callback(mixed $carry, mixed $item): mixed

Parameters and defaults

  • $array is the input array. Elements are visited in their stored order.
  • $callback receives the carry and the current item, and must return the new carry.
  • $initial is the starting carry. It defaults to null. If the array is empty, this value is returned unchanged.

On the first iteration $carry holds $initial. If you leave it out, the first callback call receives null as the carry, not the first array element. This differs from reduce functions in some other languages.

Return value and failure cases

The function returns the final carry. For an empty array it returns $initial, which is null when you did not supply one. It does not throw for an empty array, so a missing result is easy to overlook. Passing something that is not an array or not callable raises a TypeError. Since PHP 8.0.0, a callback that expects a by-reference parameter triggers an E_WARNING, so write the callback to take plain values and return the new carry.

Example 1: sums and products

The first example reduces the same list twice. The sum starts at 0, and the product starts at 10, so the product is 10 * 1 * 2 * 3 * 4 * 5.

Example
<?php
$numbers = [1, 2, 3, 4, 5];
$sum = array_reduce($numbers, fn($carry, $item) => $carry + $item, 0);
$product = array_reduce($numbers, fn($carry, $item) => $carry * $item, 10);
echo json_encode(['sum' => $sum, 'product' => $product]), "\n";
Output
{"sum":15,"product":1200}

Example 2: the empty array

When there is nothing to iterate, the callback never runs. You get back exactly what you passed as the initial value, or null if you passed nothing.

Example
<?php
$sum = fn($carry, $item) => $carry + $item;
var_dump(array_reduce([], $sum));
var_dump(array_reduce([], $sum, 'No data to reduce'));
var_dump(array_reduce([], $sum, 0));
Output
NULL
string(17) "No data to reduce"
int(0)

Example 3: building an array

The carry does not have to be a number. Here it is an array that grows as each word is filed under its first letter. Starting from [] keeps the result an array even when the input is empty.

Example
<?php
$words = ['apple', 'avocado', 'banana', 'blueberry', 'cherry'];
$grouped = array_reduce($words, function (array $carry, string $word): array {
    $letter = $word[0];
    $carry[$letter][] = $word;
    return $carry;
}, []);
echo json_encode($grouped), "\n";
Output
{"a":["apple","avocado"],"b":["banana","blueberry"],"c":["cherry"]}

Edge cases

  • No initial value: the first call gets null as $carry. Arithmetic with null works like 0, which hides the problem for sums but breaks product calculations, since null * 3 is 0. Always pass 1 as the initial value for products.
  • Keys are not passed: the callback sees only values. If you need keys, reduce over array_keys() and look up each value, or use a foreach loop.
  • Order matters: for non-commutative operations such as string concatenation or subtraction, the order of the array decides the result. There is no right-to-left variant, so reverse the array first with array_reverse() if you need one.
  • Type of the initial value: it decides the type of the empty-array result, so choose one that matches what the callback returns.
  • Typed callbacks: if you declare array $carry and forget the initial value, the first call receives null and throws a TypeError.

Common mistakes

  1. Forgetting to return the carry. A callback without return hands null to the next iteration, and the final result is usually null or wrong. Arrow functions return their expression automatically, which avoids this.
  2. Mutating outside state. Using use (&$total) inside the callback defeats the purpose. Put the accumulated state in the carry instead.
  3. Using it where a simpler function fits. For plain totals, array_sum() is clearer, and array_product() handles products. Use array_reduce() when the combining logic is custom.
  4. Treating a null result as a value. An empty input without an initial value gives null, so always provide an initial value when the array might be empty.
  5. Confusing it with array_map(). array_map() produces an array of the same length. array_reduce() collapses the array to a single result.
  • array_map() transforms each element and keeps one output per input.
  • array_filter() keeps only the elements that pass a test.
  • array_sum() and array_product() cover the two most common reductions.
  • array_count_values() counts occurrences of each distinct value.
  • array_unique() removes duplicate values.

Recap

array_reduce() folds an array into one value by calling your callback with a carry and each item. Pass an explicit initial value so that the first iteration and the empty-array case behave predictably. Make sure the callback always returns the new carry. The callback sees values only, and elements are processed in array order.

Tested examples

Sum and product with initial values
<?php
$numbers = [1, 2, 3, 4, 5];
$sum = array_reduce($numbers, fn($carry, $item) => $carry + $item, 0);
$product = array_reduce($numbers, fn($carry, $item) => $carry * $item, 10);
echo json_encode(['sum' => $sum, 'product' => $product]), "\n";
Output
{"sum":15,"product":1200}
Empty array returns the initial value
<?php
$sum = fn($carry, $item) => $carry + $item;
var_dump(array_reduce([], $sum));
var_dump(array_reduce([], $sum, 'No data to reduce'));
var_dump(array_reduce([], $sum, 0));
Output
NULL
string(17) "No data to reduce"
int(0)
Grouping words by first letter
<?php
$words = ['apple', 'avocado', 'banana', 'blueberry', 'cherry'];
$grouped = array_reduce($words, function (array $carry, string $word): array {
    $letter = $word[0];
    $carry[$letter][] = $word;
    return $carry;
}, []);
echo json_encode($grouped), "\n";
Output
{"a":["apple","avocado"],"b":["banana","blueberry"],"c":["cherry"]}