Arrays7 min readExamples run on PHP 8.5.10

uksort()

Learn how uksort() sorts an array in place by its keys with your own comparison callback, including return values, edge cases and common mistakes.

Signature

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

Purpose

uksort() sorts an array by its keys using a comparison function that you write. Each key keeps its value, so the pairs move together. Use it when the built-in key sorters such as ksort() cannot express your rule. Examples are ordering by key length, ignoring a leading article, or following a custom ranking.

The array is sorted in place. The function does not return a new array.

Signature

Parameters

  • $array: the array to sort. It is passed by reference, so you must pass a variable, not a literal or a function result. There is no default.
  • $callback: a callable that receives two keys, $a and $b. It must return an integer that is less than zero, zero, or greater than zero, meaning that $a comes before, ties with, or comes after $b. There is no default.

The spaceship operator <=>, strcmp() and strcasecmp() all return values suited to this job.

Return value and failures

Since PHP 8.2 the declared return type is true, and the function always returns true. Earlier versions declared bool, but the practical result was the same. The real effect is the reordering of the variable you passed.

Two behaviors from the manual are worth remembering:

  • If two keys compare as equal, they keep their original relative order. Before PHP 8.0.0 that order was undefined.
  • The array's internal pointer is reset to the first element.

A TypeError is raised if the first argument is not an array or the callback is not callable. If the callback throws, the exception propagates to your code.

Example 1: sort by key length

The callback compares only a property of the keys. Keys of equal length stay in their original order, because equal members are not reshuffled.

Example
<?php
$data = ["pear" => 3, "fig" => 1, "banana" => 2, "kiwi" => 5];
uksort($data, fn(int|string $a, int|string $b): int => strlen($a) <=> strlen($b));
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"fig":1,"pear":3,"kiwi":5,"banana":2}

pear and kiwi both have four characters, so pear stays ahead of kiwi.

Example 2: ignore a leading article

This follows the idea in the official manual. A helper normalizes each key before the case-insensitive comparison, so "an apple" sorts under A and "the Earth" under E.

Example
<?php
function strip_article(string $key): string
{
    return preg_replace('/^(a|an|the) /i', '', $key);
}

$data = ["John" => 1, "the Earth" => 2, "an apple" => 3, "a banana" => 4];
uksort($data, fn(string $a, string $b): int => strcasecmp(strip_article($a), strip_article($b)));
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"an apple":3,"a banana":4,"the Earth":2,"John":1}

Example 3: descending integer keys and the return value

Here the callback reverses the usual order by swapping the operands. The example also prints the return value.

Example
<?php
$data = [10 => "ten", 2 => "two", 33 => "thirty-three"];
$result = uksort($data, fn(int|string $a, int|string $b): int => $b <=> $a);
echo json_encode($result), "\n";
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
true
{"33":"thirty-three","10":"ten","2":"two"}

The result is true, and the array now runs from the largest key to the smallest.

Edge cases

  • Numeric string keys become integers. A key such as "10" is stored as the integer 10, so your callback receives an integer. Avoid strict string-only assumptions, or use a union type like int|string.
  • Empty and single-element arrays are left unchanged, and the callback may never run.
  • Keys are preserved. Unlike usort(), uksort() does not renumber anything.
  • Mixed key types need a callback that handles both integers and strings consistently. An inconsistent comparison, where A < B and B < A can both hold, gives unreliable ordering.
  • By-reference callback parameters. The manual notes that, since PHP 8.0.0, a callback that expects a parameter by reference causes an E_WARNING.

Common mistakes

  1. Comparing values instead of keys. The callback only sees keys. To order by value, use uasort() or usort().
  2. Expecting a sorted copy. The return value is just true. Writing $sorted = uksort($a, ...) does not give you an array.
  3. Returning a float. Return values are cast to int, so 0.5 and 0.99 become 0 and compare as equal. Subtracting fractional numbers is therefore risky. Use <=> instead.
  4. Returning a boolean. A callback like $a > $b only yields true or false, never a negative result, so it does not describe the ordering fully. Prefer <=>.
  5. Forgetting case rules. strcmp() is case-sensitive, so uppercase letters sort before lowercase ones. Use strcasecmp() when case should not matter.
  6. Passing a non-variable. Because the array is taken by reference, uksort(getData(), ...) is not valid.
  • usort(): sort by values with a user-defined comparison, then renumber keys.
  • uasort(): sort by values with a user-defined comparison, keeping key association.
  • ksort(): sort by keys using standard comparison flags, with no callback.
  • strcmp(), strcasecmp(), strnatcmp(): ready-made string comparisons for callbacks.

Recap

uksort() reorders an array in place by keys, using a callback that returns a negative, zero or positive integer. It keeps key-value pairs together, preserves the original order of ties, resets the internal pointer and always returns true. Use <=> for reliable results, remember that numeric string keys arrive as integers, and reach for uasort() when the ordering depends on values.

Tested examples

Sort by key length
<?php
$data = ["pear" => 3, "fig" => 1, "banana" => 2, "kiwi" => 5];
uksort($data, fn(int|string $a, int|string $b): int => strlen($a) <=> strlen($b));
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"fig":1,"pear":3,"kiwi":5,"banana":2}
Ignore a leading article
<?php
function strip_article(string $key): string
{
    return preg_replace('/^(a|an|the) /i', '', $key);
}

$data = ["John" => 1, "the Earth" => 2, "an apple" => 3, "a banana" => 4];
uksort($data, fn(string $a, string $b): int => strcasecmp(strip_article($a), strip_article($b)));
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"an apple":3,"a banana":4,"the Earth":2,"John":1}
Descending integer keys and return value
<?php
$data = [10 => "ten", 2 => "two", 33 => "thirty-three"];
$result = uksort($data, fn(int|string $a, int|string $b): int => $b <=> $a);
echo json_encode($result), "\n";
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
true
{"33":"thirty-three","10":"ten","2":"two"}