PHP sorting, usort, and the spaceship operator
Sort arrays by value or by custom rules, and combine several sort keys with <=>.
<?php
$numbers = [5, 2, 9, 1, 5, 6];
sort($numbers);
echo implode(" ", $numbers), "\n";
rsort($numbers);
echo implode(" ", $numbers), "\n";
$people = [["Ada", 30], ["Bo", 25], ["Cy", 30], ["Di", 25]];
usort($people, fn($a, $b) => $a[1] <=> $b[1] ?: strcmp($a[0], $b[0]));
echo implode(",", array_column($people, 0)), "\n";
$words = ["pear", "apple", "Fig"];
sort($words);
echo implode(",", $words), "\n";
sort($words, SORT_FLAG_CASE | SORT_STRING);
echo implode(",", $words), "\n";
$scores = ["Ada" => 90, "Bo" => 85, "Cy" => 90];
arsort($scores);
echo implode(",", array_keys($scores)), "\n";1 2 5 5 6 9 9 6 5 5 2 1 Bo,Di,Ada,Cy Fig,apple,pear apple,Fig,pear Ada,Cy,Bo
Explanation
sort and rsort order the values of an array and renumber the keys, while asort, arsort, ksort, and krsort keep the key–value pairs. Since PHP 8.0 the sorts are stable, so equal elements keep their original order. By default strings are compared as strings with capital letters first, so "Fig" sorts before "apple". The flag SORT_FLAG_CASE | SORT_STRING ignores the case.
usort takes a comparison function that returns a negative number, zero, or a positive number. The spaceship operator <=> returns exactly that for numbers and strings. The short ternary a <=> b ?: c falls through to the next key when the first comparison gives zero, which sorts by several keys. usort sorts in place and returns true.
Explore the dry run
<?php$numbers = [5, 2, 9, 1, 5, 6];sort($numbers);echo implode(" ", $numbers), "\n";rsort($numbers);echo implode(" ", $numbers), "\n"; $people = [["Ada", 30], ["Bo", 25], ["Cy", 30], ["Di", 25]];usort($people, fn($a, $b) => $a[1] <=> $b[1] ?: strcmp($a[0], $b[0]));echo implode(",", array_column($people, 0)), "\n"; $words = ["pear", "apple", "Fig"];sort($words);echo implode(",", $words), "\n";sort($words, SORT_FLAG_CASE | SORT_STRING);echo implode(",", $words), "\n"; $scores = ["Ada" => 90, "Bo" => 85, "Cy" => 90];arsort($scores);echo implode(",", array_keys($scores)), "\n";Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| Ascending order; the array is changed in place. | — | — | |
| Sorted ascending. | — | 1 2 5 5 6 9 | |
| Descending order. | — | 1 2 5 5 6 9 | |
| Compare ages first. If they are equal, <=> gives 0, which is falsy, so ?: falls through to the names. | — | 1 2 5 5 6 9 | |
| Ages 25 first (Bo, Di), then 30 (Ada, Cy), each group alphabetical. | — | 1 2 5 5 6 9 9 6 5 5 2 1 Bo,Di,Ada,Cy | |
| The default string sort puts capital letters first. | — | 1 2 5 5 6 9 9 6 5 5 2 1 Bo,Di,Ada,Cy Fig,apple,pear | |
| The flags ignore case when comparing. | — | 1 2 5 5 6 9 9 6 5 5 2 1 Bo,Di,Ada,Cy Fig,apple,pear | |
| Sort by value, highest first, keeping the keys. The sort is stable, so Ada stays before Cy. | — | 1 2 5 5 6 9 9 6 5 5 2 1 Bo,Di,Ada,Cy Fig,apple,pear | |
| Ada and Cy (90) then Bo (85). | — | 1 2 5 5 6 9 9 6 5 5 2 1 Bo,Di,Ada,Cy Fig,apple,pear apple,Fig,pear Ada,Cy,Bo |
Cost and common mistakes
O(n log n) for all of these sorts.
- Before PHP 8 the sort functions were not stable. Code that relies on stability must require PHP 8 or later.
- Mixed-type arrays compare in surprising ways. Use the explicit flags SORT_NUMERIC and SORT_STRING.
- usort returns true, not the sorted array. The array you pass in is the one that changes.
Try it yourself
How would you sort the people by age descending?
Reveal answer and reasoning
Swap the operands: usort($people, fn($a, $b) => $b[1] <=> $a[1]);