PHP Array Sorting
PHP provides a rich set of sorting functions for both indexed and associative arrays. Understanding when to use each function and how to create custom sorting logic is essential for organizing and presenting data effectively.
Basic Sorting Functions
PHP's basic sorting functions work on indexed arrays and modify the
original
array.
All sorting functions return true on success.
| Function | Description | Key Behavior |
|---|---|---|
sort() |
Sort ascending | Reindexes keys (0, 1, 2...) |
rsort() |
Sort descending | Reindexes keys (0, 1, 2...) |
shuffle() |
Randomize order | Reindexes keys (0, 1, 2...) |
array_reverse() |
Reverse order | Returns new array |
<?php
// sort() - Ascending order
$numbers = [3, 1, 4, 1, 5, 9, 2, 6];
sort($numbers);
print_r($numbers);
// Output: [1, 1, 2, 3, 4, 5, 6, 9]
// rsort() - Descending order
$letters = ["c", "a", "b", "d"];
rsort($letters);
print_r($letters);
// Output: ["d", "c", "b", "a"]
// shuffle() - Random order
$cards = ["Ace", "King", "Queen", "Jack"];
shuffle($cards);
print_r($cards);
// Output: Random order each time
?>
Sorting Flags
PHP sorting functions accept optional flags that control how values are compared. This is especially important when sorting mixed data types.
| Flag | Description | Use Case |
|---|---|---|
SORT_REGULAR |
Compare items normally (default) | General purpose |
SORT_NUMERIC |
Compare items numerically | Numbers as strings |
SORT_STRING |
Compare items as strings | Force string comparison |
SORT_NATURAL |
Natural order like humans read | "img2" before "img10" |
SORT_FLAG_CASE |
Case-insensitive (combine with SORT_STRING) | "Apple" with "banana" |
<?php
// Problem: String sorting of numbers
$versions = ["img1", "img10", "img2", "img21", "img3"];
sort($versions); // Regular sort
print_r($versions);
// Wrong: ["img1", "img10", "img2", "img21", "img3"]
sort($versions, SORT_NATURAL); // Natural sort
print_r($versions);
// Correct: ["img1", "img2", "img3", "img10", "img21"]
// Case-insensitive string sort
$names = ["alice", "Bob", "CAROL", "david"];
sort($names, SORT_STRING | SORT_FLAG_CASE);
print_r($names);
// Output: ["alice", "Bob", "CAROL", "david"]
?>
SORT_NATURAL for file names, version
numbers,
or any
data where humans expect "2" to come before "10".
Associative Array Sorting
When sorting associative arrays, you often want to preserve key-value relationships. PHP provides specialized functions for this purpose.
| Function | Sorts By | Order | Keys |
|---|---|---|---|
asort() |
Value | Ascending | Preserved |
arsort() |
Value | Descending | Preserved |
ksort() |
Key | Ascending | Preserved |
krsort() |
Key | Descending | Preserved |
<?php
$scores = [
"Alice" => 85,
"Bob" => 92,
"Carol" => 78,
"David" => 95
];
// Sort by score (value), ascending - preserve keys
asort($scores);
print_r($scores);
// Output: Carol=>78, Alice=>85, Bob=>92, David=>95
// Sort by score (value), descending
arsort($scores);
print_r($scores);
// Output: David=>95, Bob=>92, Alice=>85, Carol=>78
// Sort by name (key), ascending
ksort($scores);
print_r($scores);
// Output: Alice=>85, Bob=>92, Carol=>78, David=>95
// Sort by name (key), descending
krsort($scores);
print_r($scores);
// Output: David=>95, Carol=>78, Bob=>92, Alice=>85
?>
sort() on an associative array
will
destroy all keys and reindex with numbers. Always use
asort() or arsort() to preserve keys.
Custom Sorting with usort()
When built-in sorting isn't enough, usort() lets you define
custom
comparison logic using a callback function.
Comparison Function Rules
Your comparison function must return:
- Negative integer: if $a should come before $b
- Zero: if $a equals $b
- Positive integer: if $a should come after $b
| Function | Description | Keys |
|---|---|---|
usort() |
Custom sort by value | Reindexed |
uasort() |
Custom sort by value | Preserved |
uksort() |
Custom sort by key | Preserved |
<?php
// Sort products by price
$products = [
["name" => "Widget", "price" => 29.99],
["name" => "Gadget", "price" => 49.99],
["name" => "Gizmo", "price" => 19.99]
];
usort($products, function($a, $b) {
return $a["price"] <=> $b["price"]; // Spaceship operator
});
foreach ($products as $p) {
echo "{$p['name']}: ${$p['price']}\n";
}
// Output: Gizmo: $19.99, Widget: $29.99, Gadget: $49.99
// Using arrow function (PHP 7.4+)
usort($products, fn($a, $b) => $b["price"] <=> $a["price"]); // Descending
?>
The Spaceship Operator (<=>)
PHP 7 introduced the spaceship operator, which simplifies comparison functions by returning -1, 0, or 1 automatically.
<?php
// Without spaceship operator (old way)
function compare($a, $b) {
if ($a < $b) return -1;
if ($a > $b) return 1;
return 0;
}
// With spaceship operator (modern way)
function compare($a, $b) {
return $a <=> $b;
}
// Examples
echo 1 <=> 2; // -1 (1 is less than 2)
echo 2 <=> 2; // 0 (equal)
echo 3 <=> 2; // 1 (3 is greater than 2)
// Works with strings too
echo "apple" <=> "banana"; // -1
?>
$a and
$b
in the comparison: $b <=> $a
Multi-field Sorting
Often you need to sort by multiple criteria - for example, sort by last name, then by first name when last names are equal.
<?php
$employees = [
["last" => "Smith", "first" => "John", "age" => 30],
["last" => "Smith", "first" => "Alice", "age" => 25],
["last" => "Jones", "first" => "Bob", "age" => 35],
["last" => "Smith", "first" => "Bob", "age" => 28]
];
// Sort by last name, then first name
usort($employees, function($a, $b) {
// First compare last names
$lastCmp = $a["last"] <=> $b["last"];
if ($lastCmp !== 0) {
return $lastCmp;
}
// If last names equal, compare first names
return $a["first"] <=> $b["first"];
});
foreach ($employees as $e) {
echo "{$e['last']}, {$e['first']}\n";
}
// Output:
// Jones, Bob
// Smith, Alice
// Smith, Bob
// Smith, John
// Compact version with null coalescing-like pattern
usort($employees, fn($a, $b) =>
($a["last"] <=> $b["last"]) ?: ($a["first"] <=> $b["first"])
);
?>
?: operator (Elvis operator)
returns
the
left side if it's truthy (non-zero), otherwise the right side. Since 0 is
falsy,
it falls through to the next comparison when values are equal.
Sorting Multiple Arrays Together
array_multisort() sorts multiple arrays at once, or sorts a
multidimensional array by one or more columns.
<?php
// Sort parallel arrays together
$names = ["Carol", "Alice", "Bob"];
$ages = [30, 25, 35];
array_multisort($names, SORT_ASC, $ages);
print_r($names); // ["Alice", "Bob", "Carol"]
print_r($ages); // [25, 35, 30] - ages follow their names
// Sort multidimensional array by column
$users = [
["name" => "Alice", "score" => 85, "time" => 120],
["name" => "Bob", "score" => 85, "time" => 90],
["name" => "Carol", "score" => 92, "time" => 100]
];
// Extract columns for sorting
$scores = array_column($users, "score");
$times = array_column($users, "time");
// Sort by score DESC, then time ASC
array_multisort(
$scores, SORT_DESC,
$times, SORT_ASC,
$users
);
print_r($users);
// Carol (92, 100), Bob (85, 90), Alice (85, 120)
?>
Practical Sorting Examples
Sort by String Length
<?php
$words = ["elephant", "cat", "dog", "hippopotamus", "ant"];
usort($words, fn($a, $b) => strlen($a) <=> strlen($b));
print_r($words);
// ["ant", "cat", "dog", "elephant", "hippopotamus"]
?>
Sort Dates
<?php
$events = [
["name" => "Meeting", "date" => "2024-03-15"],
["name" => "Deadline", "date" => "2024-01-20"],
["name" => "Launch", "date" => "2024-02-28"]
];
usort($events, fn($a, $b) =>
strtotime($a["date"]) <=> strtotime($b["date"])
);
foreach ($events as $e) {
echo "{$e['date']}: {$e['name']}\n";
}
// 2024-01-20: Deadline
// 2024-02-28: Launch
// 2024-03-15: Meeting
?>
Case-Insensitive Custom Sort
<?php
$names = ["bob", "Alice", "CAROL", "David"];
usort($names, fn($a, $b) =>
strcasecmp($a, $b) // Case-insensitive comparison
);
print_r($names);
// ["Alice", "bob", "CAROL", "David"]
?>
Sort by Priority (Custom Order)
<?php
$tasks = [
["title" => "Fix bug", "priority" => "medium"],
["title" => "Deploy", "priority" => "high"],
["title" => "Update docs", "priority" => "low"],
["title" => "Code review", "priority" => "high"]
];
$priorityOrder = ["high" => 1, "medium" => 2, "low" => 3];
usort($tasks, fn($a, $b) =>
$priorityOrder[$a["priority"]] <=> $priorityOrder[$b["priority"]]
);
foreach ($tasks as $t) {
echo "[{$t['priority']}] {$t['title']}\n";
}
// [high] Deploy
// [high] Code review
// [medium] Fix bug
// [low] Update docs
?>
Try It Yourself
Experiment with PHP sorting functions in the interactive editor below.
Click Run to execute your code
Click Run to execute your code
Common Mistakes
Using sort() on Associative Arrays
<?php
// Wrong - loses keys!
$prices = ["apple" => 1.50, "banana" => 0.75];
sort($prices);
print_r($prices); // [0 => 0.75, 1 => 1.50] - keys gone!
// Correct - preserves keys
$prices = ["apple" => 1.50, "banana" => 0.75];
asort($prices);
print_r($prices); // ["banana" => 0.75, "apple" => 1.50]
?>
Forgetting Sort Modifies Original Array
<?php
$original = [3, 1, 2];
// Wrong - trying to capture return value
$sorted = sort($original); // $sorted is true/false!
// Correct - sort modifies in place
$sorted = $original; // Copy first if needed
sort($sorted);
// Now $original is unchanged, $sorted is sorted
?>
Wrong Comparison Return Values
<?php
// Wrong - returning boolean
usort($arr, fn($a, $b) => $a > $b); // Inconsistent!
// Correct - return integer
usort($arr, fn($a, $b) => $a <=> $b);
?>
Exercises
Exercise 1: Sort Products
Sort an array of products by price (ascending), then by name if prices are equal.
<?php
$products = [
["name" => "Pen", "price" => 2.50],
["name" => "Notebook", "price" => 5.00],
["name" => "Pencil", "price" => 1.00],
["name" => "Eraser", "price" => 1.00]
];
// Your code here
?>
<?php
usort($products, fn($a, $b) =>
($a["price"] <=> $b["price"]) ?: ($a["name"] <=> $b["name"])
);
foreach ($products as $p) {
echo "{$p['name']}: ${$p['price']}\n";
}
// Eraser: $1.00, Pencil: $1.00, Pen: $2.50, Notebook: $5.00
?>
Exercise 2: Sort by Age Groups
Sort users into "child" (under 18), "adult" (18-64), "senior" (65+) groups, then by name within each group.
<?php
$users = [
["name" => "Bob", "age" => 45],
["name" => "Alice", "age" => 12],
["name" => "Carol", "age" => 70],
["name" => "David", "age" => 8],
["name" => "Eve", "age" => 35]
];
// Your code here
?>
<?php
function getAgeGroup($age) {
if ($age < 18) return 1; // child
if ($age < 65) return 2; // adult
return 3; // senior
}
usort($users, function($a, $b) {
$groupCmp = getAgeGroup($a["age"]) <=> getAgeGroup($b["age"]);
return $groupCmp ?: ($a["name"] <=> $b["name"]);
});
foreach ($users as $u) {
echo "{$u['name']} ({$u['age']})\n";
}
// Alice (12), David (8), Bob (45), Eve (35), Carol (70)
?>
Exercise 3: Leaderboard Ranking
Create a leaderboard sorted by score (descending), then by fastest time (ascending) for ties, then by name alphabetically.
<?php
$players = [
["name" => "Alice", "score" => 100, "time" => 45],
["name" => "Bob", "score" => 100, "time" => 45],
["name" => "Carol", "score" => 100, "time" => 42],
["name" => "David", "score" => 95, "time" => 30]
];
// Your code here - Output with rank numbers
?>
<?php
usort($players, fn($a, $b) =>
($b["score"] <=> $a["score"]) ?: // Score DESC
($a["time"] <=> $b["time"]) ?: // Time ASC
($a["name"] <=> $b["name"]) // Name ASC
);
$rank = 1;
foreach ($players as $p) {
echo "#{$rank} {$p['name']} - Score: {$p['score']}, Time: {$p['time']}s\n";
$rank++;
}
// #1 Carol - Score: 100, Time: 42s
// #2 Alice - Score: 100, Time: 45s
// #3 Bob - Score: 100, Time: 45s
// #4 David - Score: 95, Time: 30s
?>
Summary
sort()/rsort()for indexed arrays - reindexes keysasort()/arsort()for associative arrays by value - preserves keysksort()/krsort()for associative arrays by key- Use
SORT_NATURALflag for human-friendly ordering usort()for custom sorting with comparison callback- Spaceship operator
<=>simplifies comparisons - Chain comparisons with
?:for multi-field sorting array_multisort()for sorting multiple arrays together
Enjoying these tutorials?