Web Analytics

PHP Array Sorting

Module 6: Arrays | Lesson 6 of 6

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"]
?>
Tip: Use 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
?>
Warning: Using 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
?>
Tip: To sort in descending order, simply swap $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"])
);
?>
How it works: The ?: 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.

Output
Click Run to execute your code
Output
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 keys
  • asort()/arsort() for associative arrays by value - preserves keys
  • ksort()/krsort() for associative arrays by key
  • Use SORT_NATURAL flag 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