PHPの配列ソート関数は、「値で並べるかキーで並べるか」「キーを維持するか」「比較を自分で書くか」の3点で選べます。 値で並べてキーを振り直すなら sort、キーを維持するなら asort、キーで並べるなら ksort、比較のルールを自分で決めたいなら頭に u が付く usort・uasort・uksort です。

この記事では、全ソート関数を1枚の早見表にまとめ、PHP 8.4.21 で実行した出力をそのまま載せています。多次元配列を複数のキーで並べ替える書き方、array_multisort との使い分け、日本語や数値文字列の並び替え、PHP 8 系で変わった点まで、コピーして使える形で確認できます。

PHPソート関数の早見表

関数 並べ替えの対象 キーの扱い 順序 比較方法
sort 値 0 から振り直す 昇順 標準の比較(フラグで変更可)
rsort 値 0 から振り直す 降順 標準の比較(フラグで変更可)
usort 値 0 から振り直す 自由 自作の比較関数
asort 値 維持する 昇順 標準の比較(フラグで変更可)
arsort 値 維持する 降順 標準の比較(フラグで変更可)
uasort 値 維持する 自由 自作の比較関数
ksort キー 維持する 昇順 標準の比較(フラグで変更可)
krsort キー 維持する 降順 標準の比較(フラグで変更可)
uksort キー 維持する 自由 自作の比較関数
natsort 値 維持する 昇順 自然順(大文字と小文字を区別)
natcasesort 値 維持する 昇順 自然順(大文字と小文字を区別しない)
array_multisort 値(複数の配列を連動) 文字列キーは維持、数値キーは振り直す 配列ごとに指定 標準の比較(フラグで変更可)
shuffle 値 0 から振り直す ランダム —
array_reverse 並びを逆にするだけ 数値キーは振り直す(第2引数で維持可) 逆順 —(新しい配列を返す)

名前の読み方:a は連想(associative)=キー維持、k はキー(key)、r は逆順(reverse)、u はユーザー定義(user)です。この4文字の組み合わせで、どの関数かを思い出せます。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PHP配列ソート関数一覧 sort・usort・asort・ksortの違い」

やりたいことから選ぶ逆引き表

やりたいこと 書き方
数値や文字列の配列を小さい順に sort($a);
大きい順に rsort($a);
連想配列を値で並べ、キーは残す asort($a); / arsort($a);
連想配列をキーで並べる ksort($a); / krsort($a);
多次元配列を特定の列で並べる usort($rows, fn($a, $b) => $a['price'] <=> $b['price']);
複数の列で並べる usort($rows, fn($a, $b) => [$a['x'], $a['y']] <=> [$b['x'], $b['y']]);
img2 を img10 より前に sort($a, SORT_NATURAL | SORT_FLAG_CASE);
大文字と小文字を区別せずに sort($a, SORT_STRING | SORT_FLAG_CASE);
数字の文字列を文字として並べる sort($a, SORT_STRING);
日本語を五十音順に (new Collator('ja_JP'))->sort($a);
元の配列を変えずに並べた結果がほしい コピーしてからソート(後述)
上位3件だけ取り出す arsort($a); array_slice($a, 0, 3, true);

共通の注意:配列そのものを書き換え、戻り値はtrue

ソート関数は引数の配列を直接並べ替えます(参照渡し)。戻り値は並べ替えた配列ではなく true です。

<?php
$x = [3, 1, 2];
$y = sort($x);
var_dump($y);
bool(true)

foreach (sort($x) as $v) のように戻り値を使うと、次の警告になります。

Warning: foreach() argument must be of type array|object, true given

sort($x); と1行で実行し、その後で $x を使う形にします。PHP の公式マニュアル(sort のページ)を開いて確認したところ、PHP 8.2.0 から戻り値の型が bool から true に変わったと記載されています。

基本の6関数:sort・rsort・asort・arsort・ksort・krsort

同じ連想配列を6つの関数に渡して、結果を比べます。

<?php
$base = ['b' => 3, 'a' => 1, 'd' => 10, 'c' => 2];

foreach (['sort', 'rsort', 'asort', 'arsort', 'ksort', 'krsort'] as $f) {
    $x = $base;
    $f($x);
    echo "== $f\n";
    print_r($x);
}

実行結果(PHP 8.4.21。print_r の改行は詰めています):

== sort
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 10 )
== rsort
Array ( [0] => 10 [1] => 3 [2] => 2 [3] => 1 )
== asort
Array ( [a] => 1 [c] => 2 [b] => 3 [d] => 10 )
== arsort
Array ( [d] => 10 [b] => 3 [c] => 2 [a] => 1 )
== ksort
Array ( [a] => 1 [b] => 3 [c] => 2 [d] => 10 )
== krsort
Array ( [d] => 10 [c] => 2 [b] => 3 [a] => 1 )
関数 結果の読み方
sort / rsort 値で並び、キー a〜d が 0〜3 に置き換わる
asort / arsort 値で並び、キーと値の組はそのまま
ksort / krsort キーの順に並ぶ。値は見ていない

連想配列に sort を使うとキーがなくなります。 「名前 => 点数」のような配列を値で並べるときは asort・arsort を選びます。

上位N件を取り出す

<?php
$scores = ['tanaka' => 80, 'sato' => 95, 'abe' => 80, 'ito' => 60];
arsort($scores);
print_r(array_slice($scores, 0, 3, true));
Array ( [sato] => 95 [tanaka] => 80 [abe] => 80 )

array_slice の第4引数を true にすると、数値キーの場合も含めてキーが維持されます。同点の tanaka と abe は、元の配列での順番どおりに並んでいます(PHP 8.0 以降の安定ソート。後述します)。

usort・uasort・uksort:比較ルールを自分で書く

比較関数は、2つの要素を受け取り「負の数・0・正の数」のいずれかを返す関数です。 負なら1つ目が前、正なら2つ目が前、0 なら同順位です。

PHP 7.0 で入った宇宙船演算子と、PHP 7.4 で入ったアロー関数を使うと、1行で書けます。

<?php
$base = ['b' => 3, 'a' => 1, 'd' => 10, 'c' => 2];

$x = $base;
usort($x, fn($p, $q) => $p <=> $q);          // 値の昇順、キーは振り直す
print_r($x);

$x = $base;
uasort($x, fn($p, $q) => $q <=> $p);         // 値の降順、キーは維持
print_r($x);

$x = $base;
uksort($x, fn($p, $q) => strcmp($q, $p));    // キーの降順
print_r($x);
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 10 )
Array ( [d] => 10 [b] => 3 [c] => 2 [a] => 1 )
Array ( [d] => 10 [c] => 2 [b] => 3 [a] => 1 )
式 返す値 意味
$a <=> $b -1 / 0 / 1 昇順
$b <=> $a -1 / 0 / 1 降順(左右を入れ替えるだけ)
strcmp($a, $b) 負 / 0 / 正 文字列として比較
strcasecmp($a, $b) 負 / 0 / 正 大文字と小文字を区別しない
strnatcmp($a, $b) -1 / 0 / 1 自然順
version_compare($a, $b) -1 / 0 / 1 バージョン番号として比較

比較関数は整数を返す

比較関数で $a > $b のように真偽値を返したり、小数の引き算をそのまま返したりすると、意図した並びにならないことがあります。

エラーになる例(真偽値を返している)

<?php
$x = [3, 1, 2];
usort($x, fn($a, $b) => $a > $b);
Deprecated: usort(): Returning bool from comparison function is deprecated, return an integer less than, equal to, or greater than zero

意図どおりに並ばない例(小数の引き算)

<?php
$x = [0.5, 0.2, 0.9, 0.1];
usort($x, fn($a, $b) => $a - $b);
echo json_encode($x), "\n";

usort($x, fn($a, $b) => $a <=> $b);
echo json_encode($x), "\n";
[0.5,0.2,0.9,0.1]
[0.1,0.2,0.5,0.9]

1つ目は並び替わっていません。比較関数の戻り値は整数として扱われるため、0.3 や -0.4 といった差が 0(同順位)とみなされたためです。数値の比較は引き算ではなく <=> を使うと、整数・小数・文字列のどれでも正しく -1 / 0 / 1 が返ります。

多次元配列を並べ替える

ここからは、次の備品データを使います。

<?php
$items = [
    ['id' => 1, 'name' => 'ノート',     'category' => '文具', 'price' => 300,  'stock' => 12],
    ['id' => 2, 'name' => 'マウス',     'category' => 'PC',   'price' => 1800, 'stock' => 5],
    ['id' => 3, 'name' => 'ペン',       'category' => '文具', 'price' => 120,  'stock' => 40],
    ['id' => 4, 'name' => 'キーボード', 'category' => 'PC',   'price' => 1800, 'stock' => 3],
    ['id' => 5, 'name' => '付箋',       'category' => '文具', 'price' => 300,  'stock' => 8],
];

function show(array $rows): void {
    foreach ($rows as $k => $r) {
        echo "[$k] ", json_encode($r, JSON_UNESCAPED_UNICODE), "\n";
    }
}

1つの列で並べる

usort($items, fn($a, $b) => $a['price'] <=> $b['price']);
show($items);
[0] {"id":3,"name":"ペン","category":"文具","price":120,"stock":40}
[1] {"id":1,"name":"ノート","category":"文具","price":300,"stock":12}
[2] {"id":5,"name":"付箋","category":"文具","price":300,"stock":8}
[3] {"id":2,"name":"マウス","category":"PC","price":1800,"stock":5}
[4] {"id":4,"name":"キーボード","category":"PC","price":1800,"stock":3}

降順にするには $b['price'] <=> $a['price'] と左右を入れ替えます。同じ価格のノート(id 1)と付箋(id 5)は、元の順番のまま並んでいます。

複数の列で並べる:配列どうしを比較する

「カテゴリの昇順 → 価格の降順 → 在庫の昇順」のような複数キーのソートは、配列どうしを <=> で比べると1行で書けます。 配列の比較は先頭の要素から順に行われ、差が出たところで結果が決まります。

usort($items, fn($a, $b) =>
    [$a['category'], $b['price'], $a['stock']]
    <=>
    [$b['category'], $a['price'], $b['stock']]
);
show($items);
[0] {"id":4,"name":"キーボード","category":"PC","price":1800,"stock":3}
[1] {"id":2,"name":"マウス","category":"PC","price":1800,"stock":5}
[2] {"id":5,"name":"付箋","category":"文具","price":300,"stock":8}
[3] {"id":1,"name":"ノート","category":"文具","price":300,"stock":12}
[4] {"id":3,"name":"ペン","category":"文具","price":120,"stock":40}

降順にしたい列だけ、左右の配列で $a と $b を入れ替えるのがコツです(上の例では price)。

複数の列で並べる:エルビス演算子でつなぐ

もう1つの書き方は、比較結果が 0(同順位)のときだけ次の比較に進む形です。

usort($items, fn($a, $b) =>
    strcmp($a['category'], $b['category'])
    ?: $b['price'] <=> $a['price']
    ?: $a['stock'] <=> $b['stock']
);

結果は上と同じ並びになりました。列ごとに strcmp や strnatcmp など比較方法を変えたいときは、こちらの書き方が向いています。

書き方 向いている場面 20万件での所要時間(手元の計測)
配列どうしの <=> 列が多く、読みやすさを優先したい 0.67 秒
?: でつなぐ 列ごとに比較関数を変えたい、少しでも速くしたい 0.39 秒
array_multisort 件数が多く、標準の比較で足りる 0.11 秒

(2列の整数キーで 20 万件を並べ替えた1回の計測値です。環境やデータによって変わるので、傾向の目安としてご覧ください。)

キーを維持して並べる

行のキーに意味がある場合(ID をキーにしている等)は uasort を使います。

uasort($items, fn($a, $b) => $a['price'] <=> $b['price']);
show($items);
[2] {"id":3,"name":"ペン","category":"文具","price":120,"stock":40}
[0] {"id":1,"name":"ノート","category":"文具","price":300,"stock":12}
[4] {"id":5,"name":"付箋","category":"文具","price":300,"stock":8}
[1] {"id":2,"name":"マウス","category":"PC","price":1800,"stock":5}
[3] {"id":4,"name":"キーボード","category":"PC","price":1800,"stock":3}

比較関数を使い回す

列名と向きを引数に取り、比較関数を返す関数を作っておくと、呼び出し側が短くなります。

<?php
function by(string $key, bool $desc = false): Closure {
    return fn($a, $b) => $desc ? $b[$key] <=> $a[$key] : $a[$key] <=> $b[$key];
}

$items = [['id' => 1, 'price' => 300], ['id' => 2, 'price' => 1800], ['id' => 3, 'price' => 120]];
usort($items, by('price', true));
echo json_encode(array_column($items, 'id')), "\n";
[2,1,3]

オブジェクトの配列を並べる

オブジェクトでも書き方は同じです。DateTimeImmutable どうしは <=> で比較できます。

<?php
final class Task {
    public function __construct(
        public string $title,
        public int $priority,
        public DateTimeImmutable $due,
    ) {}
}

$tasks = [
    new Task('B', 2, new DateTimeImmutable('2026-10-05')),
    new Task('A', 1, new DateTimeImmutable('2026-10-09')),
    new Task('C', 2, new DateTimeImmutable('2026-10-01')),
];

// 優先度の高い順 → 期限の早い順
usort($tasks, fn(Task $a, Task $b) => [$b->priority, $a->due] <=> [$a->priority, $b->due]);

foreach ($tasks as $t) {
    echo $t->title, ' p', $t->priority, ' ', $t->due->format('Y-m-d'), "\n";
}
C p2 2026-10-01
B p2 2026-10-05
A p1 2026-10-09

決まった順番・nullを最後に・文字数順

<?php
// 1) 自分で決めた順番(high → mid → low)
$order = ['high' => 0, 'mid' => 1, 'low' => 2];
$x = ['low', 'high', 'mid', 'high'];
usort($x, fn($a, $b) => $order[$a] <=> $order[$b]);
echo json_encode($x), "\n";

// 2) null を最後に回す
$x = [3, null, 1, null, 2];
usort($x, fn($a, $b) => [$a === null, $a] <=> [$b === null, $b]);
echo json_encode($x), "\n";

// 3) 文字数の短い順 → 同じ長さなら文字順
$w = ['banana', 'fig', 'apple', 'kiwi'];
usort($w, fn($a, $b) => [strlen($a), $a] <=> [strlen($b), $b]);
echo json_encode($w), "\n";
["high","high","mid","low"]
[1,2,3,null,null]
["fig","kiwi","apple","banana"]

日本語の文字数で比べるときは strlen(バイト数)ではなく mb_strlen を使います。

元の配列を変えずに、並べた結果を受け取る

PHP の配列は値渡しでコピーされるので、関数の中でソートして返せば、元の配列はそのまま残ります。

<?php
function sorted(array $a, callable $cmp): array {
    usort($a, $cmp);
    return $a;
}

$original = [3, 1, 2];
$result = sorted($original, fn($a, $b) => $a <=> $b);
echo json_encode([$original, $result]), "\n";
[[3,1,2],[1,2,3]]

array_multisortとarray_columnの使い分け

array_multisort は、複数の配列を「連動させて」並べ替える関数です。 最初の配列で並べ、同じ値のところは次の配列で比べ、最後に渡した配列まで同じ順に並べ替えます。

<?php
$names  = ['c', 'a', 'b'];
$scores = [70, 90, 80];
array_multisort($scores, SORT_DESC, $names);
echo json_encode([$scores, $names]), "\n";
[[90,80,70],["a","b","c"]]

多次元配列では、array_column で列を取り出して並べ替えの基準にします。

array_multisort(
    array_column($items, 'category'), SORT_ASC,  SORT_STRING,
    array_column($items, 'price'),    SORT_DESC, SORT_NUMERIC,
    $items
);
show($items);
[0] {"id":2,"name":"マウス","category":"PC","price":1800,"stock":5}
[1] {"id":4,"name":"キーボード","category":"PC","price":1800,"stock":3}
[2] {"id":1,"name":"ノート","category":"文具","price":300,"stock":12}
[3] {"id":5,"name":"付箋","category":"文具","price":300,"stock":8}
[4] {"id":3,"name":"ペン","category":"文具","price":120,"stock":40}

array_multisortで知っておきたい2点

1. 配列の長さがそろっていないとエラーになります。

ValueError: Array sizes are inconsistent

2. 基準の列が同じ値のとき、次に渡した配列(行そのもの)で比較されます。 元の順番が保たれるわけではありません。

<?php
$data = [['n' => 'b', 'v' => 2], ['n' => 'a', 'v' => 2], ['n' => 'c', 'v' => 1]];
array_multisort(array_column($data, 'v'), SORT_ASC, $data);
echo json_encode(array_column($data, 'n')), "\n";   // array_multisort

$data = [['n' => 'b', 'v' => 2], ['n' => 'a', 'v' => 2], ['n' => 'c', 'v' => 1]];
usort($data, fn($a, $b) => $a['v'] <=> $b['v']);
echo json_encode(array_column($data, 'n')), "\n";   // usort
["c","a","b"]
["c","b","a"]

v が同じ 2 件について、usort は元の順(b → a)を保ち、array_multisort は行どうしを比べて a → b に並べました。同順位のときの並びまで決めたい場合は、基準の列を明示的に追加すると結果が安定します。

観点 usort + <=> array_multisort + array_column
読みやすさ 比較の内容が1か所にまとまる 列・向き・フラグを並べて書く
比較の自由度 高い(関数を自由に書ける) 標準の比較とフラグの範囲
同順位の扱い 元の順番を保つ 次に渡した配列で比較
速度(手元の20万件) 0.39〜0.67 秒 0.11 秒
キー 振り直す(uasort なら維持) 文字列キーは維持、数値キーは振り直す

ふだんは usort、件数が多くて速度を優先したいときは array_multisort という選び方がおすすめです。

array_columnで「キー => 値」にしてからソートする

array_column の第3引数でキーにする列を指定すると、asort や ksort がそのまま使える形になります。

$prices = array_column($items, 'price', 'name');   // 名前 => 価格
asort($prices);
echo json_encode($prices, JSON_UNESCAPED_UNICODE), "\n";

$byId = array_column($items, null, 'id');          // id => 行全体
krsort($byId);
echo json_encode(array_keys($byId)), "\n";
{"ペン":120,"ノート":300,"付箋":300,"マウス":1800,"キーボード":1800}
[5,4,3,2,1]

ソートフラグ:数値文字列・自然順・大文字小文字

sort・rsort・asort・arsort・ksort・krsort・array_multisort は、第2引数(array_multisort は各配列の後ろ)にフラグを渡して比較方法を変えられます。フラグの一覧は公式マニュアルの sort のページで確認しました。

フラグ 比較方法
SORT_REGULAR(既定) 通常の比較演算子と同じ
SORT_NUMERIC 数値として比較
SORT_STRING 文字列として比較
SORT_LOCALE_STRING 現在のロケール(setlocale)に基づいて文字列比較
SORT_NATURAL 自然順(natsort と同じ並び)
SORT_FLAG_CASE SORT_STRING か SORT_NATURAL と組み合わせて、大文字と小文字を区別しない

数字の文字列を並べる

<?php
$n = ['10', '9', '2', '1'];

$x = $n; sort($x);               print_r($x);
$x = $n; sort($x, SORT_STRING);  print_r($x);
$x = $n; sort($x, SORT_NUMERIC); print_r($x);
Array ( [0] => 1 [1] => 2 [2] => 9 [3] => 10 )     ← 既定
Array ( [0] => 1 [1] => 10 [2] => 2 [3] => 9 )     ← SORT_STRING
Array ( [0] => 1 [1] => 2 [2] => 9 [3] => 10 )     ← SORT_NUMERIC

数字だけの文字列どうしは、既定でも数値として比較されます。 郵便番号や型番のように「文字として」並べたいときは SORT_STRING を指定します。

既定の比較では '1e1'・'10'・'010'・'10.0' がすべて同じ値とみなされる点も覚えておくと役立ちます(手元では '1e3' == '1000' が true でした)。コードや ID を並べるときは SORT_STRING を付けておくと、見た目どおりの文字順になります。

ファイル名を自然順に並べる

<?php
$f = ['img12.png', 'img10.png', 'IMG2.png', 'img1.png'];

$x = $f; sort($x);                                   print_r($x);
$x = $f; sort($x, SORT_NATURAL);                     print_r($x);
$x = $f; sort($x, SORT_NATURAL | SORT_FLAG_CASE);    print_r($x);
$x = $f; natsort($x);                                print_r($x);
$x = $f; natcasesort($x);                            print_r($x);
Array ( [0] => IMG2.png [1] => img1.png [2] => img10.png [3] => img12.png )   ← sort
Array ( [0] => IMG2.png [1] => img1.png [2] => img10.png [3] => img12.png )   ← SORT_NATURAL
Array ( [0] => img1.png [1] => IMG2.png [2] => img10.png [3] => img12.png )   ← SORT_NATURAL | SORT_FLAG_CASE
Array ( [2] => IMG2.png [3] => img1.png [1] => img10.png [0] => img12.png )   ← natsort
Array ( [3] => img1.png [2] => IMG2.png [1] => img10.png [0] => img12.png )   ← natcasesort
書き方 自然順 大文字小文字 キー
sort($a, SORT_NATURAL) する 区別する(大文字が先) 振り直す
sort($a, SORT_NATURAL | SORT_FLAG_CASE) する 区別しない 振り直す
natsort($a) する 区別する 維持する
natcasesort($a) する 区別しない 維持する

natsort はキーを維持するので、foreach で回すと並べ替えた順に出てきますが、$x[0] は元の先頭要素のままです。添字でアクセスしたいときは sort($a, SORT_NATURAL | SORT_FLAG_CASE) を使うか、array_values でキーを振り直します。

バージョン番号を並べる

<?php
$v = ['v1.10', 'v1.9', 'v1.2'];
sort($v);                      echo json_encode($v), "\n";
sort($v, SORT_NATURAL);        echo json_encode($v), "\n";
usort($v, 'version_compare');  echo json_encode($v), "\n";
["v1.10","v1.2","v1.9"]
["v1.2","v1.9","v1.10"]
["v1.2","v1.9","v1.10"]

大文字と小文字を区別せずに並べる

<?php
$x = ['banana', 'apple', 'Cherry'];
sort($x);                                print_r($x);
sort($x, SORT_STRING | SORT_FLAG_CASE);  print_r($x);
Array ( [0] => Cherry [1] => apple [2] => banana )
Array ( [0] => apple [1] => banana [2] => Cherry )

既定では文字コード順なので、大文字が小文字より先に並びます。

日付の文字列を並べる

2026-10-03 のようにゼロ埋めされた形式は、文字列としてそのまま並べられます。ゼロ埋めされていない値が混ざる場合は、日付に変換して比べます。

<?php
$d = ['2026-10-03', '2026-9-30', '2026-10-01'];
sort($d);
echo json_encode($d), "\n";

usort($d, fn($a, $b) => strtotime($a) <=> strtotime($b));
echo json_encode($d), "\n";
["2026-10-01","2026-10-03","2026-9-30"]
["2026-9-30","2026-10-01","2026-10-03"]

日本語を並べる:Collatorと読みがな

sort で日本語を並べると、文字コード(UTF-8 のバイト列)の順になります。

<?php
$j = ['佐藤', '鈴木', '阿部', 'さとう', 'アベ', 'すずき', '田中'];
$x = $j;
sort($x);
echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";
["さとう","すずき","アベ","佐藤","田中","鈴木","阿部"]

ひらがな → カタカナ → 漢字の順になり、「アベ」が「すずき」の後ろに来ています。

intl拡張のCollatorで五十音順にする

ひらがなとカタカナを混ぜて五十音順に並べたいときは、intl 拡張の Collator が使えます(php -m に intl が表示されていれば利用できます。手元は ICU 74.2)。

<?php
$j = ['佐藤', '鈴木', '阿部', 'さとう', 'アベ', 'すずき', '田中'];
$c = new Collator('ja_JP');

$x = $j;
$c->sort($x);                                  // キーを振り直す
echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";

$x = ['b' => 'すずき', 'a' => 'アベ', 'c' => 'さとう'];
$c->asort($x);                                 // キーを維持
echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";

// 多次元配列では compare を比較関数に使う
$rows = [['n' => 'すずき'], ['n' => 'アベ'], ['n' => 'さとう']];
usort($rows, fn($a, $b) => $c->compare($a['n'], $b['n']));
echo json_encode($rows, JSON_UNESCAPED_UNICODE), "\n";
["アベ","さとう","すずき","阿部","佐藤","田中","鈴木"]
{"a":"アベ","c":"さとう","b":"すずき"}
[{"n":"アベ"},{"n":"さとう"},{"n":"すずき"}]

かなは「アベ → さとう → すずき」と五十音順になりました。漢字は読みではなく、文字ごとに定められた順で並びます(阿部 → 佐藤 → 田中 → 鈴木)。プログラムは「佐藤」の読みを知らないためです。

Collator には数字を数値として扱う設定もあります。

$c2 = new Collator('en');
$c2->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
$x = ['file10', 'file9', 'File2'];
$c2->sort($x);
echo json_encode($x), "\n";
["File2","file9","file10"]

漢字の名前は「読みがな」の列で並べる

漢字を読みの順に並べたいときは、読みがなの列を別に持ち、その列で並べるのが確実です。

<?php
$members = [
    ['name' => '佐藤', 'kana' => 'サトウ'],
    ['name' => '阿部', 'kana' => 'アベ'],
    ['name' => '鈴木', 'kana' => 'スズキ'],
];
usort($members, fn($a, $b) => strcmp($a['kana'], $b['kana']));
echo json_encode(array_column($members, 'name'), JSON_UNESCAPED_UNICODE), "\n";
["阿部","佐藤","鈴木"]

読みがなをカタカナ(またはひらがな)に統一しておけば、strcmp だけで五十音順になります。

SORT_LOCALE_STRINGを使う場合

SORT_LOCALE_STRING は、setlocale で設定したロケールの規則で並べます。ドイツ語のロケール(de_DE.utf8)で試した結果です。

<?php
setlocale(LC_COLLATE, 'de_DE.utf8');
$g = ['Zebra', 'Äpfel', 'Apfel', 'Öl'];
$x = $g; sort($x);                      echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";
$x = $g; sort($x, SORT_LOCALE_STRING);  echo json_encode($x, JSON_UNESCAPED_UNICODE), "\n";
["Apfel","Zebra","Äpfel","Öl"]
["Apfel","Äpfel","Öl","Zebra"]

結果はサーバーにインストールされているロケールに左右されます。環境が変わっても同じ結果にしたい場合は Collator のほうが扱いやすいでしょう。

PHP 8系で変わった点

バージョン 変更点 確認方法
7.0 宇宙船演算子 <=> が使える 一般に知られた仕様(PHP 7 では未実行)
7.4 アロー関数 fn() => が使える 一般に知られた仕様(PHP 7 では未実行)
8.0 ソートが安定になった(同順位の要素は元の順番を保つ) 公式マニュアルの sort のページ+8.4.21 で実行
8.0 数値と、数値でない文字列の比較方法が変わった 公式の 8.0 移行ガイド+8.4.21 で実行
8.2 sort などの戻り値の型が bool から true に 公式マニュアルの sort のページ

この記事の実行結果はすべて PHP 8.4.21 のものです。PHP 7 系の挙動は手元では未実行で、公式マニュアルと移行ガイドの記載にもとづいています。

PHP 8.0から安定ソートになった

安定ソートとは、比較して同順位になった要素が、元の配列での順番を保つソートのことです。 公式マニュアルには「PHP 8.0.0 より前は、同順位の要素の相対的な順序は未定義だった」と書かれています。

// 価格で並べる:同じ 300 の id 1 と 5、同じ 1800 の id 2 と 4 は元の順のまま
usort($items, fn($a, $b) => $a['price'] <=> $b['price']);
echo implode(',', array_column($items, 'id')), "\n";
3,1,5,2,4

1,000 件のデータで「同じキーの要素が元の順番どおりか」を調べるコードも実行し、すべて元の順番が保たれていることを確かめました。

安定ソートのおかげで、「優先度の低いキーから順に、2回ソートする」という書き方もできます。

usort($items, fn($a, $b) => $a['stock'] <=> $b['stock']);       // 先に在庫順
usort($items, fn($a, $b) => $a['category'] <=> $b['category']); // 次にカテゴリ順
echo implode(',', array_column($items, 'id')), "\n";
4,2,5,1,3

カテゴリごとにまとまり、その中は在庫の少ない順になっています。PHP 7 系でも動かすコードでは、同順位の順番に頼らず、複数キーを1つの比較関数に書いておくと結果がそろいます。

数値と文字列の比較が変わった

PHP 8.0 の移行ガイドによると、数値と「数値でない文字列」を比べるとき、PHP 8.0 以降は数値のほうを文字列に変換して比較します(PHP 7 系では文字列のほうを数値に変換していました)。

比較 PHP 7 系(移行ガイドの記載) PHP 8.0 以降(8.4.21 で実行)
0 == "foo" true false
0 == "" true false
42 == "42foo" true false
0 == "0" true true
42 == " 42" true true

ソートは内部で同じ比較を使うので、数値と文字列が混ざった配列の並びに影響します。PHP 8.4.21 での結果です。

<?php
$m = [10, '9', 'abc', 2, '1e1', '10'];

$x = $m; sort($x);               print_r($x);
$x = $m; sort($x, SORT_STRING);  print_r($x);
Array ( [0] => 2 [1] => 9 [2] => 10 [3] => 1e1 [4] => 10 [5] => abc )
Array ( [0] => 10 [1] => 10 [2] => 1e1 [3] => 2 [4] => 9 [5] => abc )
var_dump(0 <=> 'foo');     // int(-1)  0 は "foo" より前
var_dump('abc' <=> 5);     // int(1)   "abc" は 5 より後ろ
var_dump('10' <=> '9');    // int(1)   数字どうしは数値として比較
var_dump('10' <=> '9a');   // int(-1)  片方が数値でなければ文字列として比較

PHP 8 系では、数値でない文字列は数値より後ろに並びます。公式マニュアルも「型が混ざった配列を既定のフラグでソートするときは注意」と案内しています。型が混ざる可能性がある配列は、SORT_STRING か SORT_NUMERIC を明示するか、usort で比較方法を決めておくと、バージョンによらず同じ結果になります。

つまずきやすい点と直し方

症状 原因 直し方
$sorted = sort($a) が true になる 戻り値は並べ替え後の配列ではない sort($a); の後で $a を使う
連想配列のキーが 0,1,2 になった sort・usort はキーを振り直す asort・uasort を使う
img10 が img2 より前に来る 文字コード順で比べている SORT_NATURAL か natsort
小数の配列が並び替わらない 比較関数で引き算の結果を返している <=> を使う
Deprecated: Returning bool ... 比較関数が真偽値を返している <=> で整数を返す
natsort の後に $a[0] が先頭にならない キーが維持されている array_values($a) で振り直す
ひらがなとカタカナが別々に並ぶ 文字コード順で比べている Collator か、読みがなの列で並べる
'1e1' と '10' が同じ扱いになる 数値文字列として比較されている SORT_STRING を指定
ValueError: Array sizes are inconsistent array_multisort に渡した配列の長さが違う array_column の結果の件数を確認

よくある質問

Q. sort と usort はどちらを使えばよいですか? A. 数値や文字列だけの配列を昇順・降順に並べるなら sort・rsort が簡潔です。多次元配列の特定の列で並べたい、複数の条件で並べたい、独自の順番にしたい場合は usort を使います。

Q. 降順にする usort の書き方は? A. 比較の左右を入れ替えて fn($a, $b) => $b['price'] <=> $a['price'] とします。複数キーのときは、降順にしたい列だけ左右を入れ替えます。

Q. ランダムに並べ替えるには? A. shuffle($a) を使います。キーは 0 から振り直されます。シード値を指定して再現したい場合は、PHP 8.2 以降の Random\Randomizer の shuffleArray が使えます(手元の 8.4.21 で、Mt19937 エンジンにシード 1 を渡して動作することを確かめました)。

Q. 並べ替えた後、連番のキーに戻したいときは? A. array_values($a) で 0 からの連番に振り直せます。asort や natsort の結果を JSON の配列として出力したいときにも使えます。

まとめ

  • 値で並べてキーを振り直すなら sort、キーを維持するなら asort、キーで並べるなら ksort。r が付くと降順、u が付くと比較関数を自分で書ける。
  • ソート関数は配列を直接書き換え、戻り値は true。結果は元の変数から読む。
  • 多次元配列は usort と <=>。複数キーは配列どうしの比較か ?: でつなぐ。
  • array_multisort と array_column の組み合わせは高速。同順位の扱いが usort と異なる点を押さえておく。
  • 数字入りの文字列は SORT_NATURAL、コードや ID は SORT_STRING、日本語のかなは Collator、漢字は読みがなの列で並べる。
  • PHP 8.0 から安定ソートになり、同順位の要素は元の順番を保つ。
  • PHP 8.0 で数値と文字列の比較が変わったので、型が混ざる配列はフラグか比較関数で比較方法を明示する。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PHP配列ソート関数一覧 sort・usort・asort・ksortの違い」

株式会社RJCでは、PHPの配列操作やソートの使い分けを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?