はじめに
前回の記事では、値をユーザー定義の比較関数でソートしつつキーを保持する uasort() を解説しました。今回紹介する uksort() は、それとよく似ていますがソートの対象が「値」ではなく「キー」であるという点が異なります。
uksort() は、配列のキーを独自の比較関数で並び替えるための関数です。名前の “u” は “user-defined”(ユーザー定義)、”k” は “key”(キー)を意味します。文字列キーを数値的に比較したい、キーに含まれるバージョン番号順に並べたい、特定の優先順位リストに従ってキーを並べ替えたい、といった場面で活躍します。本記事では基本的な使い方から実践的な活用例まで詳しく解説します。
関数概要
| 項目 | 内容 |
|---|---|
| 関数名 | uksort() |
| 所属拡張 | コア関数(標準で常に利用可能) |
| シグネチャ | uksort(array &$array, callable $callback): bool |
| 引数1 | $array — ソート対象の配列(参照渡し) |
| 引数2 | $callback — 2つのキーを比較するコールバック関数 |
| 戻り値 | 成功時に true |
| 対応バージョン | PHP 4以降 |
| ソート対象 | 配列のキー(値ではない) |
| 類似関数 | uasort()(値をソート、キー保持)、ksort()(キーの標準比較) |
ソートの流れ(イメージ図)
ソート前の配列
['v10' => '安定版', 'v2' => '旧版', 'v1' => '最古版']
│
▼
uksort($array, function($a, $b) {
return (int)substr($a, 1) <=> (int)substr($b, 1);
})
│
┌──────────────┴──────────────────┐
│ キー同士を比較関数で比較する │
│ (単純な文字列比較では "v10" < "v2" になってしまう) │
│ 数値として比較することで正しい順序に │
└──────────────┬──────────────────┘
▼
ソート後の配列(キーの順序が変わり、値も一緒に移動する)
['v1' => '最古版', 'v2' => '旧版', 'v10' => '安定版']
ポイントは、"v2" と "v10" のような文字列キーを単純な文字列比較でソートすると "v10" が "v2" より前に来てしまう(辞書順では "1" は "2" より小さい)という問題です。uksort() を使えば、こうしたケースでも独自の比較ロジックによって意図した順序(数値としての大小関係)でソートできます。
実践サンプル7選
例1:基本的な使い方
<?php
class BasicUksortDemo
{
public function sortByKey(array $data): array
{
// キー同士を比較する関数を指定する
uksort($data, fn ($a, $b) => $a <=> $b);
return $data;
}
}
$demo = new BasicUksortDemo();
$data = ['banana' => 3, 'apple' => 1, 'cherry' => 2];
print_r($demo->sortByKey($data));
// ['apple' => 1, 'banana' => 3, 'cherry' => 2] ← キーのアルファベット順
例2:バージョン番号を含むキーを正しい順序でソートする
<?php
class VersionKeySorter
{
/**
* "v1", "v2", "v10" のようなキーを
* 文字列順ではなく数値として正しくソートする
*/
public function sort(array $versions): array
{
uksort($versions, function (string $a, string $b) {
$numA = (int) substr($a, 1);
$numB = (int) substr($b, 1);
return $numA <=> $numB;
});
return $versions;
}
}
$sorter = new VersionKeySorter();
$versions = ['v10' => '安定版', 'v2' => '旧版', 'v1' => '最古版'];
print_r($sorter->sort($versions));
// ['v1' => '最古版', 'v2' => '旧版', 'v10' => '安定版']
例3:カスタム優先順位リストに基づいてキーを並び替える
<?php
class PriorityKeySorter
{
/**
* @var array<string, int> キー名 => 優先順位のマップ
*/
private array $priorityMap;
public function __construct(array $priorityOrder)
{
// 配列の並び順から優先順位のマップを生成しておく
$this->priorityMap = array_flip($priorityOrder);
}
public function sort(array $data): array
{
uksort($data, function ($a, $b) {
$priorityA = $this->priorityMap[$a] ?? PHP_INT_MAX;
$priorityB = $this->priorityMap[$b] ?? PHP_INT_MAX;
return $priorityA <=> $priorityB;
});
return $data;
}
}
$sorter = new PriorityKeySorter(['name', 'email', 'phone', 'address']);
$formData = ['address' => '東京都', 'name' => '太郎', 'phone' => '090-xxxx', 'email' => 'a@example.com'];
print_r($sorter->sort($formData));
// 指定した優先順位(name, email, phone, address)通りに並び替わる
例4:大文字小文字を区別しないキーソート
<?php
class CaseInsensitiveKeySorter
{
/**
* キーの大文字小文字を無視してアルファベット順にソートする
*/
public function sort(array $data): array
{
uksort($data, fn ($a, $b) => strcasecmp((string) $a, (string) $b));
return $data;
}
}
$sorter = new CaseInsensitiveKeySorter();
$data = ['Banana' => 1, 'apple' => 2, 'Cherry' => 3];
print_r($sorter->sort($data));
// ['apple' => 2, 'Banana' => 1, 'Cherry' => 3]
例5:日付形式のキーを時系列順にソートする
<?php
class DateKeySorter
{
/**
* "2026-08-05" のような日付文字列をキーに持つ配列を
* 時系列順にソートする
*/
public function sortChronologically(array $dailyLogs): array
{
uksort($dailyLogs, function (string $a, string $b) {
$timeA = strtotime($a);
$timeB = strtotime($b);
return $timeA <=> $timeB;
});
return $dailyLogs;
}
}
$sorter = new DateKeySorter();
$logs = [
'2026-08-05' => '通常運用',
'2026-07-30' => 'メンテナンス実施',
'2026-08-01' => '障害対応',
];
print_r($sorter->sortChronologically($logs));
例6:多次元配列のキー(グループ名)を自然順ソートする
<?php
class NaturalKeySorter
{
/**
* strnatcmp()を利用して、
* "item2" と "item10" のようなキーを自然な順序でソートする
*/
public function sort(array $data): array
{
uksort($data, fn ($a, $b) => strnatcmp((string) $a, (string) $b));
return $data;
}
}
$sorter = new NaturalKeySorter();
$data = ['item10' => 'C', 'item2' => 'B', 'item1' => 'A'];
print_r($sorter->sort($data));
// ['item1' => 'A', 'item2' => 'B', 'item10' => 'C'] ← 自然な順序
例7:設定ファイルのセクションキーを重要度でグルーピングしながらソート
<?php
class ConfigSectionSorter
{
private const IMPORTANCE = [
'database' => 1,
'cache' => 2,
'logging' => 3,
];
/**
* 定義済みの重要度マップに存在するキーを優先し、
* それ以外のキーはアルファベット順で後ろに並べる
*/
public function sort(array $config): array
{
uksort($config, function ($a, $b) {
$importanceA = self::IMPORTANCE[$a] ?? null;
$importanceB = self::IMPORTANCE[$b] ?? null;
if ($importanceA !== null && $importanceB !== null) {
return $importanceA <=> $importanceB;
}
if ($importanceA !== null) {
return -1;
}
if ($importanceB !== null) {
return 1;
}
return strcmp((string) $a, (string) $b);
});
return $config;
}
}
$sorter = new ConfigSectionSorter();
$config = ['mail' => [], 'cache' => [], 'database' => [], 'app' => []];
print_r($sorter->sort($config));
// ['database' => [], 'cache' => [], 'app' => [], 'mail' => []]
関連関数との比較
| 関数 | 役割 | uksortとの違い |
|---|---|---|
uksort() | キーをユーザー定義の比較関数でソート | 本記事の対象。ソート対象は「キー」 |
uasort() | 値をユーザー定義の比較関数でソート(キー保持) | ソート対象が「値」である点が異なる |
usort() | 値をユーザー定義の比較関数でソート | キーが保持されず連番に振り直される |
ksort() | キーの標準的な比較でソート | 独自の比較ロジックを指定できない点が異なる |
krsort() | キーの標準的な比較で降順ソート | uksort()で降順にする場合は比較関数の引数順を入れ替える |
よくある落とし穴(注意点)
- 比較関数はキーを受け取ることを忘れない
uksort()のコールバックに渡されるのは配列の「値」ではなく「キー」です。uasort()と混同して値を前提とした比較ロジックを書いてしまうと、意図しない結果になります。 - キーの型が数値か文字列かを意識する PHPの配列キーは数値または文字列ですが、比較関数内で暗黙の型変換に依存すると予期しない挙動になることがあります。必要に応じて
(int)や(string)で明示的にキャストしましょう。 - 単純な文字列比較では数値を含むキーが期待通りにならない
"v2"と"v10"の例のように、文字列としての辞書順比較では直感に反する結果になることがあります。数値部分を抽出して比較する、またはstrnatcmp()を使うことで解決できます(例2・例6を参照)。 - 元の値との対応関係は崩れない
uksort()はキーの順序だけを並び替える関数であり、各キーに対応する値は移動先に一緒についていきます。値だけを個別に並び替えるわけではない点を理解しておきましょう。 - 重い比較処理はパフォーマンスに影響する
uasort()と同様、比較関数内で複雑な処理を行うと要素数に応じて呼び出し回数が増加します。優先順位マップなど、事前に計算できるデータはループの外で用意しておくのが望ましいです(例3・例7を参照)。
まとめ
| 観点 | まとめ |
|---|---|
| 何をする関数か | ユーザー定義の比較関数を使って配列の「キー」を並び替える |
| 主な用途 | バージョン番号順のソート、優先順位に基づく並び替え、自然順ソートなど |
| ソート対象 | キー(値ではない)。値はキーに追従して移動する |
| 類似関数との違い | uasort()は値をソート、uksort()はキーをソートする |
| 注意点 | コールバックに渡されるのはキーであること、数値を含む文字列キーの比較方法 |
uksort() は、配列のキーそのものに意味がある場合に非常に役立つ関数です。バージョン番号や日付、独自の優先順位リストなど、標準の ksort() では対応できない複雑な並び替えロジックが必要なときは、ぜひ uksort() の活用を検討してみてください。
