Spaceship Operator
What Is the Spaceship Operator? In simple terms: The spaceship operator <=> compares two values and tells you which one is smaller, or whether they are equal — all in one result. Technically: &l
What Is the Spaceship Operator?
In simple terms: The spaceship operator <=> compares two values and tells you which one is smaller, or whether they are equal — all in one result.
Technically: <=> is the three-way comparison operator, introduced in PHP 7.0. It returns an integer:
| Expression | Result |
|---|---|
$a <=> $b when $a < $b | -1 |
$a <=> $b when $a == $b | 0 |
$a <=> $b when $a > $b | 1 |
The name comes from its shape, which resembles a small spaceship.
Why It Exists
Sorting functions such as usort() need a comparison function that answers "should $a come before, after, or at the same position as $b?" by returning a negative number, zero, or a positive number. Before PHP 7, this required a nested ternary or several if statements. <=> produces exactly that answer in one expression.
Basic Usage
Example
<?php
var_dump(1 <=> 2);
var_dump(2 <=> 2);
var_dump(3 <=> 2);
var_dump(1.5 <=> 1.5);
var_dump("apple" <=> "banana");
var_dump("a" <=> "B");
var_dump("10" <=> "9");
var_dump([1, 2, 3] <=> [1, 2, 4]);
Output
int(-1)
int(0)
int(1)
int(0)
int(-1)
int(1)
int(1)
int(-1)
How It Works
<=> follows the same rules as the <, ==, and > operators:
- Numbers are compared numerically.
- Non-numeric strings are compared byte by byte, so
"a"(97) is greater than"B"(66) — uppercase letters sort before lowercase ones. - Numeric strings (
"10","9") are compared as numbers, so"10" <=> "9"is1. - Arrays are compared element by element (an array with fewer elements is smaller).
Since all type-juggling rules of loose comparison apply, compare values of the same type for predictable results.
Equivalent Without the Spaceship
The spaceship operator replaces this pattern:
<?php
function compareOld(int $a, int $b): int
{
if ($a < $b) {
return -1;
}
if ($a > $b) {
return 1;
}
return 0;
}
function compareNew(int $a, int $b): int
{
return $a <=> $b;
}
var_dump(compareOld(4, 9) === compareNew(4, 9));
Output
bool(true)
Sorting With usort()
How usort() Uses the Result
usort($array, $callback) sorts an array using your comparison function. For each pair of elements, the callback must return:
- a negative number if
$ashould come before$b, - zero if they are equal for sorting purposes,
- a positive number if
$ashould come after$b.
$a <=> $b gives ascending order. Swapping the operands, $b <=> $a, gives descending order.
Example: Sorting Products by Price
<?php
$products = [
['name' => 'Mouse', 'price' => 799],
['name' => 'Keyboard', 'price' => 1499],
['name' => 'USB Cable', 'price' => 199],
['name' => 'Webcam', 'price' => 1499],
];
usort($products, fn(array $a, array $b): int => $a['price'] <=> $b['price']);
foreach ($products as $product) {
echo "{$product['name']}: ₹{$product['price']}\n";
}
Output
USB Cable: ₹199
Mouse: ₹799
Keyboard: ₹1499
Webcam: ₹1499
How It Works
- The arrow function receives two products and compares their prices.
KeyboardandWebcamhave the same price, so the comparison returns0. Since PHP 8.0, sorting is stable: elements that compare as equal keep their original order, soKeyboardstays beforeWebcam.usort()sorts the array in place and re-indexes it from0.
Descending Order
<?php
usort($products, fn(array $a, array $b): int => $b['price'] <=> $a['price']);
Placing $b on the left reverses the order: the most expensive products come first.
Sorting by Multiple Fields
Arrays are compared element by element, from the first element to the last. This makes multi-level sorting very concise: build an array of sort keys for each item.
Example: Price Descending, Then Name Ascending
<?php
$products = [
['name' => 'Webcam', 'price' => 1499],
['name' => 'Mouse', 'price' => 799],
['name' => 'Keyboard', 'price' => 1499],
['name' => 'USB Cable', 'price' => 199],
];
usort($products, fn(array $a, array $b): int =>
[$b['price'], $a['name']] <=> [$a['price'], $b['name']]
);
foreach ($products as $product) {
echo "{$product['name']}: ₹{$product['price']}\n";
}
Output
Keyboard: ₹1499
Webcam: ₹1499
Mouse: ₹799
USB Cable: ₹199
How It Works
- The left array is
[$b['price'], $a['name']]and the right array is[$a['price'], $b['name']]. - PHP first compares the first elements:
$b['price'] <=> $a['price']. Because$bis on the left, higher prices come first (descending). - Only when prices are equal does PHP compare the second elements:
$a['name'] <=> $b['name'], which sorts names ascending. KeyboardandWebcamshare a price, so they are ordered by name.
To change the direction of any key, swap $a and $b for that position only.
Sorting Other Kinds of Data
Dates
DateTime and DateTimeImmutable objects can be compared directly:
<?php
$events = [
['title' => 'Workshop', 'date' => new DateTimeImmutable('2026-11-20')],
['title' => 'Webinar', 'date' => new DateTimeImmutable('2026-10-15')],
['title' => 'Meetup', 'date' => new DateTimeImmutable('2026-12-02')],
];
usort($events, fn($a, $b) => $a['date'] <=> $b['date']);
foreach ($events as $event) {
echo $event['date']->format('d M') . " - {$event['title']}\n";
}
Output
15 Oct - Webinar
20 Nov - Workshop
02 Dec - Meetup
Case-Insensitive and Natural String Order
<=> compares strings byte by byte. That order is not what people expect when text mixes uppercase and lowercase letters or contains numbers:
<?php
$files = ['img12.png', 'IMG2.png', 'img10.png', 'img1.png'];
usort($files, fn($a, $b) => $a <=> $b);
echo implode(', ', $files) . "\n";
usort($files, 'strnatcasecmp');
echo implode(', ', $files) . "\n";
Output
IMG2.png, img1.png, img10.png, img12.png
img1.png, IMG2.png, img10.png, img12.png
- With
<=>,IMG2.pngcomes first only because uppercase letters have lower byte values than lowercase ones. The digits are compared one character at a time, soimg10would also come before a lowercaseimg2. strnatcasecmp()ignores case and treats embedded numbers as numbers, giving the order a person expects: 1, 2, 10, 12. It can be passed directly as the callback by name.
For names in specific languages, use Collator::compare() from the intl extension, which follows the sorting rules of a locale.
Common Mistakes
Returning a Boolean From a Comparison Callback
<?php
$numbers = [3, 1, 2];
usort($numbers, fn($a, $b) => $a > $b);
Output
PHP Deprecated: usort(): Returning bool from comparison function is deprecated, return an integer less than, equal to, or greater than zero in /path/script.php on line 3
A boolean only says "greater or not" — it cannot express "less than" and "equal" separately. PHP 8 still sorts the array by working around it, but warns that this is deprecated. Return $a <=> $b.
Subtracting Values Instead of Comparing
usort($items, fn($a, $b) => $a['rating'] - $b['rating']);
Subtraction seems to work for integers, but with floats it fails: a difference such as 0.4 is converted to the integer 0, so the two items are treated as equal and may end up in the wrong order. With very large integers, subtraction can also overflow. <=> has neither problem.
Comparing Mixed Types
Effect: Loose comparison rules (for example, numeric strings compared as numbers) produce surprising orders.
Fix: Normalize values to one type before sorting.
Expecting <=> to Sort Strings Naturally or Case-Insensitively
Effect: Uppercase words come first; "img10" sorts before "img2".
Fix: Use strcasecmp(), strnatcasecmp(), or Collator.
Reversing Direction for All Keys by Accident
Effect: In multi-key sorts, swapping the entire arrays reverses every key.
Fix: Swap $a and $b only for the keys that should be descending.
Best Practices
- Use
$a <=> $bfor ascending and$b <=> $afor descending comparisons. - Sort by several fields by comparing arrays of keys.
- Return integers from comparison callbacks — never booleans, and avoid subtraction.
- Compare values of a consistent type; compare dates as date objects.
- Use dedicated functions (
strnatcasecmp(),Collator) for human-friendly string ordering.
Official reference: https\://www.php.net/manual/en/language.operators.comparison.php