PHP の sort() や asort() は手軽ですが、「価格の安い順」「名前の五十音順」「連想配列の特定のキーで並べたい」といった独自の条件で並び替えたいときには物足りません。そんなときに使うのが usort() と、その仲間の uasort()・uksort() です。この記事では、比較関数を自分で書いて配列を自由に並び替える方法を、よくあるユースケースとともに解説します。連想配列やオブジェクトの配列を思い通りに並べたい初心者〜中級者の方が対象です。
目次
usort は「比較のルール」を自分で決められる
usort() は「user sort(ユーザー定義のソート)」の略で、2つの要素をどう比べるかを関数で渡して並び替えます。先頭の u が付くソート関数(usort/uasort/uksort)は、すべてこの「比較関数を自分で書く」タイプです。
比較関数は2つの引数 $a と $b を受け取り、次のルールで整数を返します。この戻り値を見て、PHP がどちらを前に置くかを決めます。
| 比較関数の戻り値 | 意味 |
|---|---|
負の数(例: -1) | $a を $b より前に置く |
0 | 順序を変えない(同じ扱い) |
正の数(例: 1) | $a を $b より後ろに置く |
基本の使い方(数値で並び替える)
まずは単純な数値の昇順で見てみます。数値の比較は $a - $b でも書けますが、現在は3つの値(負・0・正)を一度に返せる宇宙船演算子 <=>を使うのが定番です。$a <=> $b は、左が小さければ負、等しければ0、大きければ正を返します。
<?php
$scores = [80, 30, 95, 50];
// 昇順(小さい順)に並び替える
usort($scores, function ($a, $b) {
return $a <=> $b;
});
print_r($scores);
// Array ( [0] => 30 [1] => 50 [2] => 80 [3] => 95 )
降順(大きい順)にしたいときは、$a と $b を入れ替えて $b <=> $a と書くだけです。usort() は配列を直接書き換え、成功すると true を返します。元の配列を残したい場合は、渡す前にコピーしておきましょう。
なお usort() は処理後にキーを 0 から振り直す点に注意してください。元のキー(添字)を保ったまま並び替えたい場合は、後述の uasort() を使います。
連想配列を特定のキーで並び替える
実務でいちばん多いのが、「商品リストを価格順に」のように、連想配列の中の特定のキーで並び替えるケースです。比較関数の中で、それぞれの要素の比べたい値を取り出して <=> で比較します。
<?php
$products = [
["name" => "りんご", "price" => 300],
["name" => "みかん", "price" => 120],
["name" => "ぶどう", "price" => 480],
];
// price の安い順に並び替える
usort($products, function ($a, $b) {
return $a["price"] <=> $b["price"];
});
foreach ($products as $p) {
echo "{$p['name']}: {$p['price']}円\n";
}
// みかん: 120円
// りんご: 300円
// ぶどう: 480円
PHP 7.4 以降ならアロー関数を使って、もっと短く書けます。1つの式だけで済む比較なら、こちらのほうが読みやすいでしょう。
<?php
// アロー関数(fn)で同じ並び替えを短く書く
usort($products, fn($a, $b) => $a["price"] <=> $b["price"]);
2つ目の条件で並び替える(タイブレーク)
「価格が同じなら名前順にしたい」のように、第1条件が同点のときの並び順も決めたいことがあります。その場合は、最初の比較結果が 0 だったときに次の比較を行うように書きます。?:(省略形の三項演算子)を使うと、「左が 0 でなければ左、0 なら右」を簡潔に表現できます。
<?php
$users = [
["name" => "Bob", "age" => 30],
["name" => "Alice", "age" => 30],
["name" => "Carol", "age" => 25],
];
// 年齢の昇順、同じ年齢なら名前のアルファベット順
usort($users, function ($a, $b) {
return ($a["age"] <=> $b["age"])
?: ($a["name"] <=> $b["name"]);
});
foreach ($users as $u) {
echo "{$u['name']} ({$u['age']})\n";
}
// Carol (25)
// Alice (30)
// Bob (30)
uasort と uksort の違い
usort() はキーを振り直してしまうため、連想配列の「キーと値の対応」を保ったまま値で並べたいときは uasort() を使います。また、値ではなくキーそのもので並び替えたいときは uksort() を使います。3つの違いを表にまとめます。
| 関数 | 比較に使うもの | キーの扱い |
|---|---|---|
usort() | 値 | 0 から振り直す |
uasort() | 値 | 元のキーを保持する |
uksort() | キー | 元のキーを保持する |
<?php
$stock = ["banana" => 12, "apple" => 30, "cherry" => 5];
// 値(在庫数)の昇順。キーと値の対応は保つ
uasort($stock, fn($a, $b) => $a <=> $b);
print_r($stock);
// Array ( [cherry] => 5 [banana] => 12 [apple] => 30 )
// キー(名前)のアルファベット順
uksort($stock, fn($a, $b) => $a <=> $b);
print_r($stock);
// Array ( [apple] => 30 [banana] => 12 [cherry] => 5 )
並び順がおかしくなるときの原因
比較関数が整数以外を返している
比較関数は負・0・正の整数を返す必要があります。$a > $b のように true/false(真偽値)を返すと、PHP 8 では false が 0、true が 1 として扱われ、「小さい」ことを表現できないため正しく並びません。必ず <=> や引き算で整数を返しましょう。文字列の比較も <=> なら辞書順で正しく比較できます。
usort なのにキーを残したいと思っている
「並び替えたらキーが 0、1、2… に変わってしまった」というのは usort() の仕様どおりの動作です。連想配列のキーを保ちたいなら uasort() を、キー基準で並べたいなら uksort() を選びます。目的に合った関数を使えば、意図しないキーの振り直しを避けられます。
まとめ
usort() 系の関数を使えば、配列を自分のルールで自由に並び替えられます。要点を振り返ります。
- 比較関数は
$a・$bを受け取り、負・0・正の整数を返す - 数値も文字列も
$a <=> $b(宇宙船演算子)で比較するのが定番 - 連想配列の特定キーで並べるなら、関数内でその値を取り出して比較する
usortはキーを振り直し、uasortは値で・uksortはキーで並べキーを保持する
まずは連想配列を価格順に並べる例から試し、タイブレークや uasort への置き換えに広げていくと、実務で扱う複雑な並び替えにも対応できるようになります。