Arrays7 min readExamples run on PHP 8.5.10

usort()

Learn how PHP 8.4 usort() sorts an array in place with your own comparison callback, including return values, key reindexing and common pitfalls.

Signature

usort(array &$array, callable $callback): true

Purpose

usort() reorders an array by its values using a comparison callback that you write. The built-in sort() only knows PHP's standard ordering. usort() is the tool to reach for when the order depends on your own rules: sorting records by a field, ordering by several fields in turn, or ranking values with a custom priority.

The function works in place. It changes the variable you pass in rather than returning a sorted copy.

Signature

The callback has this shape:

function callback(mixed $a, mixed $b): int

Parameters

  • $array: the array to sort. It is taken by reference, so it must be a variable, not a literal or a function result. There is no default value.
  • $callback: any PHP callable, such as a closure, an arrow function, a function name string, or a [ClassName::class, 'method'] pair. It receives two elements and must return an integer that is negative, zero or positive. Negative means the first argument comes first, zero means they are equal for sorting purposes, and positive means the second comes first.

Return value and failure cases

usort() always returns true. Since the return type is true, there is no failure value to check, and testing the result is rarely useful. The interesting outcome is the changed array.

If the callback is not callable, PHP throws a TypeError. If the callback declares a by-reference parameter, PHP 8.0 and later emit an E_WARNING.

Example: a simple custom order

The spaceship operator <=> returns exactly the -1, 0 or 1 that a comparison callback needs. Swapping the operands gives a descending order.

Example
<?php
$numbers = [10, 2, 33, 4];
$result = usort($numbers, fn(int $a, int $b): int => $b <=> $a);
echo json_encode($result), "\n";
echo json_encode($numbers), "\n";
Output
true
[33,10,4,2]

The first line shows the constant true return value, and the second shows the array after sorting.

Example: sorting by several fields

Comparing two arrays with <=> compares them element by element, so you can build a multi-level sort by placing the fields in priority order.

Example
<?php
$people = [
    ['first' => 'Adam', 'last' => 'West'],
    ['first' => 'Alec', 'last' => 'Baldwin'],
    ['first' => 'Adam', 'last' => 'Baldwin'],
];
usort($people, fn(array $a, array $b): int => [$a['last'], $a['first']] <=> [$b['last'], $b['first']]);
echo json_encode($people, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
[{"first":"Adam","last":"Baldwin"},{"first":"Alec","last":"Baldwin"},{"first":"Adam","last":"West"}]

The last name decides the order first. The first name is only used when the last names are equal.

Example: keys are replaced and ties stay stable

Two behaviours matter here. First, usort() assigns fresh numeric keys starting at 0, so any original string keys are discarded. Second, from PHP 8.0 the sort is stable: elements that compare as equal keep their original relative order.

Example
<?php
$items = [
    'x' => ['name' => 'pear', 'size' => 2],
    'y' => ['name' => 'fig', 'size' => 1],
    'z' => ['name' => 'plum', 'size' => 2],
];
usort($items, fn(array $a, array $b): int => $a['size'] <=> $b['size']);
echo json_encode($items, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
[{"name":"fig","size":1},{"name":"pear","size":2},{"name":"plum","size":2}]

The keys x, y and z are gone. pear stays ahead of plum because both have size 2 and pear came first in the input.

Edge cases

  • Empty and single-element arrays are left unchanged, and the callback is not needed to decide anything.
  • Mixed types are compared by whatever your callback does. If you use <=> on mixed values, PHP's standard comparison rules apply, which can give surprising results.
  • Nested arrays and objects are passed to the callback as the elements themselves, so you can read fields directly.

Common mistakes

  1. Returning a float. The return value is cast to an integer. A difference such as 0.5 or 0.1 becomes 0, so those values are treated as equal and the order may not change. Use <=> instead of subtracting floats.
  2. Expecting keys to survive. If the keys carry meaning, use uasort() to keep them or uksort() to sort by key.
  3. Using the result as the sorted array. The function returns true, not the array. Write usort($data, ...) and then use $data.
  4. Inconsistent callbacks. A callback that does not give a consistent ordering, for example one that never returns a negative value, produces an order that cannot be trusted.
  5. Subtracting for integers carelessly. Subtraction is fine for small integers but can overflow for extreme values. <=> is safer and clearer.
  • uasort() sorts by value with a custom callback and keeps the keys.
  • uksort() sorts by key with a custom callback.
  • sort() and rsort() sort values with the standard comparison and reindex them.
  • array_multisort() sorts several arrays or columns at once.

Recap

usort() sorts an array in place using a callback that returns a negative, zero or positive integer. It always returns true, replaces all keys with a fresh 0-based list, and keeps equal elements in their original order. Prefer the spaceship operator inside the callback and never rely on float return values.

Tested examples

Sort numbers in descending order
<?php
$numbers = [10, 2, 33, 4];
$result = usort($numbers, fn(int $a, int $b): int => $b <=> $a);
echo json_encode($result), "\n";
echo json_encode($numbers), "\n";
Output
true
[33,10,4,2]
Sort records by last name, then first name
<?php
$people = [
    ['first' => 'Adam', 'last' => 'West'],
    ['first' => 'Alec', 'last' => 'Baldwin'],
    ['first' => 'Adam', 'last' => 'Baldwin'],
];
usort($people, fn(array $a, array $b): int => [$a['last'], $a['first']] <=> [$b['last'], $b['first']]);
echo json_encode($people, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
[{"first":"Adam","last":"Baldwin"},{"first":"Alec","last":"Baldwin"},{"first":"Adam","last":"West"}]
Keys are replaced and equal items keep their order
<?php
$items = [
    'x' => ['name' => 'pear', 'size' => 2],
    'y' => ['name' => 'fig', 'size' => 1],
    'z' => ['name' => 'plum', 'size' => 2],
];
usort($items, fn(array $a, array $b): int => $a['size'] <=> $b['size']);
echo json_encode($items, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
[{"name":"fig","size":1},{"name":"pear","size":2},{"name":"plum","size":2}]