Collection::sum

Adds up every item in a collection, optionally reading one key or a closure from each row.

Signature
public function sum(callable|string|null $callback = null): mixed

Parameters

ParameterTypeDescription
$callbackoptional(callable(TValue): mixed)|string|null= nullA key to read from each item (dot notation supported), or a closure returning the number to add for that item. Omit to sum the items themselves.

Return value

mixedThe running total, starting from integer 0. Returns int when every summed value is an int, float as soon as one float is involved, and 0 for an empty collection.

Errors

Throws TypeError on PHP 8 if an item resolves to a non-numeric string, an array or an object, because the values are combined with the + operator.

sum folds the collection down to a single number with reduce, starting from integer 0. With no argument it adds the items themselves; with a string it reads that key from each row; with a closure it adds whatever the closure returns.

When to reach for it

Almost always with an argument. A collection of rows — cart lines, invoice items, API records — is the common case, and sum('qty') beats array_sum(array_column(...)) because the key goes through data_get, so dot paths like sum('meta.weight') and object properties both work.

Reach for the closure form when the number does not exist as a field yet: sum(fn ($line) => $line['qty'] * $line['unit']) is the line-total pattern, and it avoids a throwaway map.

What trips people up

The seed is integer 0, not null, so an empty collection sums to 0 rather than null — convenient, but it means you cannot distinguish "no rows" from "rows totalling zero" by the return value alone. Check isEmpty() first if that matters.

Money is the other trap. Summing floats accumulates binary rounding error; sum integer minor units (cents) and format at the end.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Total an order by multiplying quantity by unit price on each line
  • Add up the file sizes of an uploaded batch before checking a quota
  • Sum a numeric column out of a decoded JSON API response
  • Produce per-group totals by combining groupBy with sum

Frequently asked questions

How do I sum one column of an array of arrays in Laravel?

Pass the column name: collect($rows)->sum('price'). The string is resolved with data_get, so it also works for object properties and dot paths like 'meta.price'.

Why does sum() return 0 instead of null for an empty collection?

Because sum() is implemented as a reduce seeded with integer 0, so the seed is what comes back when there is nothing to fold. Call isEmpty() first if you need to tell "no rows" apart from "total of zero".

Why is my sum() total slightly wrong, like 2.8000000000000003?

You are summing floats, and binary floating point cannot represent values like 0.1 exactly. Store and sum money as integer minor units (cents) and divide only when formatting for display.

More examples

Money as integer cents

The integer sum is exact and only becomes a decimal at display time. The final var_dump shows why: adding seven floats produces 2.8000000000000003, so the strict comparison against 2.8 fails. Any total you will later compare, store or reconcile should be summed as minor units.

Example · php
<?php

$payments = collect([
    ['label' => 'Deposit',   'cents' => 1050],
    ['label' => 'Balance',   'cents' => 2075],
    ['label' => 'Surcharge', 'cents' => 320],
]);

$total = $payments->sum('cents');

echo $total, "\n";
echo number_format($total / 100, 2), "\n";

// Compare with the float version, which drifts:
$floats = collect([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7]);
var_dump($floats->sum() === 2.8);

// Output:
// 3445
// 34.45
// bool(false)

Totals per group

groupBy turns the flat list into a collection of collections keyed by region, map replaces each inner collection with its own sum, and sortDesc orders the resulting scalars. The group keys survive the map, which is why the output is still keyed by region name.

Example · php
<?php

$sales = collect([
    ['region' => 'north', 'amount' => 120],
    ['region' => 'south', 'amount' => 80],
    ['region' => 'north', 'amount' => 45],
    ['region' => 'south', 'amount' => 200],
    ['region' => 'east',  'amount' => 15],
]);

$byRegion = $sales
    ->groupBy('region')
    ->map(fn ($rows) => $rows->sum('amount'))
    ->sortDesc();

print_r($byRegion->all());

// Output:
// Array
// (
//     [south] => 280
//     [north] => 165
//     [east] => 15
// )

Summing a nested field with dot notation

The string argument is resolved with data_get, so dot paths reach into nested arrays and objects. A row missing the path resolves to null, and null contributes 0 to the total rather than raising an error, so rows with absent data are silently skipped.

Example · php
<?php

$shipments = collect([
    ['id' => 1, 'parcel' => ['weight' => 340]],
    ['id' => 2, 'parcel' => ['weight' => 1200]],
    ['id' => 3, 'parcel' => ['weight' => 85]],
]);

echo $shipments->sum('parcel.weight'), "\n";

// data_get returns null for a missing path, and null + int is 0 + int.
$partial = $shipments->push(['id' => 4]);

echo $partial->sum('parcel.weight'), "\n";

// Output:
// 1625
// 1625

Discussion

  • Be the first to comment on this lesson.