【PHP8.x】SplPriorityQueue::compare()メソッドの使い方
compareメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
compareメソッドは、SplPriorityQueueにおいて、要素の優先度を比較し、その順序を決定するために使用されるメソッドです。SplPriorityQueueは、追加された要素を優先度に基づいて自動的に並べ替え、最も優先度の高い要素から取り出せるようにする特別なデータ構造です。このcompareメソッドは、新しい要素がキューに追加される際や、キュー内部で要素の順序を調整する必要がある場合に、どの要素がより高い優先度を持つかを判断するために、キューの内部で自動的に呼び出されます。
具体的には、このメソッドは2つの優先度、例えば$priority1と$priority2を引数として受け取ります。そして、これらの優先度を比較した結果を整数値で返します。$priority1が$priority2よりも高い優先度を持つと判断される場合は正の数を、低い優先度を持つ場合は負の数を、そして両者の優先度が同じ場合はゼロを返します。
SplPriorityQueueのデフォルトの実装では、数値が大きいほど優先度が高いと判断されるようにcompareメソッドが動作します。もし、このデフォルトの挙動を変更したい場合、例えば「数値が小さいほど優先度が高い」といった独自の優先度ルールを適用したい場合は、SplPriorityQueueクラスを継承し、このcompareメソッドをオーバーライドすることで、独自の比較ロジックを定義できます。これにより、アプリケーションの特定の要件に合わせた柔軟な優先度管理を実現できます。
構文(syntax)
1<?php 2 3class MyCustomPriorityQueue extends SplPriorityQueue 4{ 5 /** 6 * 2つの優先順位を比較します。 7 * 8 * @param mixed $priority1 比較する最初の優先順位。 9 * @param mixed $priority2 比較する2番目の優先順位。 10 * @return int $priority1 が $priority2 より優先度が低い場合は負の整数、等しい場合は0、高い場合は正の整数を返します。 11 */ 12 protected function compare(mixed $priority1, mixed $priority2): int 13 { 14 // ここにカスタムの比較ロジックを記述します。 15 // 例: 値が大きいほど優先度が高い 16 if ($priority1 === $priority2) { 17 return 0; 18 } 19 return ($priority1 > $priority2) ? 1 : -1; 20 } 21}
引数(parameters)
mixed $priority1, mixed $priority2
- mixed $priority1: 比較対象となる1つ目の優先度
- mixed $priority2: 比較対象となる2つ目の優先度
戻り値(return)
int
SplPriorityQueue::compare()メソッドは、2つの要素の優先度を比較した結果を整数で返します。返り値は、最初の要素が2番目の要素よりも優先度が高い場合は正の値、低い場合は負の値、等しい場合は0となります。
サンプルコード
PHP SplPriorityQueue で配列を比較する
1<?php 2 3/** 4 * SplPriorityQueue を継承し、配列を優先度として比較するカスタムキュー。 5 * 6 * このクラスは、SplPriorityQueue のデフォルトの比較ロジックをオーバーライドし、 7 * 優先度として与えられた配列の内容に基づいて要素の優先順位を決定します。 8 * 9 * 想定される優先度配列の形式: 10 * ['level' => int, 'timestamp' => int] 11 * 12 * 比較ロジック: 13 * 1. 'level' が高いほど優先度が高い。 14 * 2. 'level' が同じ場合は、'timestamp' が新しい(大きい)ほど優先度が高い。 15 */ 16class CustomArrayPriorityQueue extends SplPriorityQueue 17{ 18 /** 19 * 2つの優先度を比較し、どちらがより高い優先度を持つかを決定します。 20 * SplPriorityQueue::compare メソッドをオーバーライドし、 21 * 配列形式の優先度をカスタムロジックで比較します。 22 * 23 * @param mixed $priority1 比較する最初の優先度(配列形式を想定)。 24 * @param mixed $priority2 比較する2番目の優先度(配列形式を想定)。 25 * @return int 26 * - 正の数 ($priority1 が $priority2 より優先度が高い場合) 27 * - 負の数 ($priority1 が $priority2 より優先度低い場合) 28 * - 0 ($priority1 と $priority2 の優先度が同じ場合) 29 */ 30 protected function compare(mixed $priority1, mixed $priority2): int 31 { 32 // 配列の 'level' キーを比較します。 33 // 'level' が高いほど優先度が高いとします。 34 if ($priority1['level'] > $priority2['level']) { 35 return 1; // $priority1 の level が高いので、優先度が高い 36 } 37 if ($priority1['level'] < $priority2['level']) { 38 return -1; // $priority2 の level が高いので、優先度が高い 39 } 40 41 // 'level' が同じ場合は、配列の 'timestamp' キーを比較します。 42 // 'timestamp' が大きい(新しい)ほど優先度が高いとします。 43 if ($priority1['timestamp'] > $priority2['timestamp']) { 44 return 1; // $priority1 の timestamp が新しいので、優先度が高い 45 } 46 if ($priority1['timestamp'] < $priority2['timestamp']) { 47 return -1; // $priority2 の timestamp が新しいので、優先度が高い 48 } 49 50 // 'level' も 'timestamp' も同じ場合、優先度は同じです。 51 return 0; 52 } 53} 54 55// ------------------------------------------------------------------------- 56// 以下は CustomArrayPriorityQueue の使用例です。 57// ------------------------------------------------------------------------- 58 59// 新しいカスタム優先度キューを作成します。 60$queue = new CustomArrayPriorityQueue(); 61 62echo "要素と配列形式の優先度をキューに追加します。\n"; 63 64// 要素とそれに対応する優先度配列をキューに挿入します。 65// insert(mixed $value, mixed $priority) の形式です。 66$queue->insert('緊急タスク A', ['level' => 3, 'timestamp' => time() - 3600]); // レベル3, 1時間前 67$queue->insert('通常タスク B', ['level' => 1, 'timestamp' => time() - 7200]); // レベル1, 2時間前 68$queue->insert('重要タスク C', ['level' => 2, 'timestamp' => time() - 1800]); // レベル2, 30分前 69$queue->insert('緊急タスク D', ['level' => 3, 'timestamp' => time()]); // レベル3, 現在時刻 (最も新しい) 70$queue->insert('通常タスク E', ['level' => 1, 'timestamp' => time() - 900]); // レベル1, 15分前 71 72echo "キューの要素数: " . $queue->count() . "個\n\n"; 73 74echo "優先度の高い順に要素を取り出します:\n"; 75// キューが空になるまで要素を取り出します。 76// CustomArrayPriorityQueue::compare メソッドのロジックに基づいて、 77// 高い level のものが先に、同じ level の場合は新しい timestamp のものが先に取得されます。 78while (!$queue->isEmpty()) { 79 $element = $queue->extract(); // 最も優先度の高い要素を取り出します。 80 echo "- " . $element . "\n"; 81} 82 83echo "\n--- 期待される取り出し順序 ---\n"; 84echo "1. 緊急タスク D (level:3, timestamp:最新)\n"; 85echo "2. 緊急タスク A (level:3, timestamp:古い)\n"; 86echo "3. 重要タスク C (level:2, timestamp:中程度)\n"; 87echo "4. 通常タスク E (level:1, timestamp:新しい)\n"; 88echo "5. 通常タスク B (level:1, timestamp:最も古い)\n";
PHPのSplPriorityQueue::compareメソッドは、PHP 8で提供されるSplPriorityQueueクラスに属し、キュー内の要素の優先順位を決定するために使用されます。このメソッドをオーバーライドすることで、デフォルトの数値比較ではなく、配列やオブジェクトといった複雑なデータ構造を優先度として扱い、独自の比較ロジックを定義することが可能になります。
引数には比較対象となる二つの優先度$priority1と$priority2が渡されます。戻り値は整数型で、$priority1が$priority2より優先度が高い場合は正の数、低い場合は負の数、両者の優先度が同じ場合は0を返す必要があります。この戻り値に基づいて、SplPriorityQueueは要素の取り出し順序を決定します。
サンプルコードでは、SplPriorityQueueを継承したCustomArrayPriorityQueueクラスがcompareメソッドをオーバーライドしています。ここでは、優先度として['level' => int, 'timestamp' => int]形式の配列を使用しています。カスタム比較ロジックは、まずlevelの値が高い方を優先し、levelが同じ場合はtimestampの値が大きい(新しい)方を優先するように実装されています。これにより、キューに挿入された「緊急タスク D」のようなlevelが高くtimestampが最新の要素が最も高い優先度を持つと判断され、他の要素より先に取り出される、といった柔軟な優先度管理が実現されます。この機能は、タスクスケジューラやイベント処理など、複数の条件で優先順位をつけたい場面で非常に役立ちます。
このサンプルコードは、SplPriorityQueueの優先度比較ロジックを、配列の値を基にカスタマイズする方法を示しています。compareメソッドの引数はmixed型ですが、この実装では['level' => int, 'timestamp' => int]形式の配列を前提としています。もしキューに、この形式と異なる構造のデータや配列ではない値が優先度として渡されると、「未定義のキー」エラーが発生するなど、プログラムが予期せぬ動作をしたり停止したりする可能性があります。そのため、insertメソッドで優先度を渡す際は、必ずcompareメソッドが想定する配列形式であることを確認し、型の一貫性を保つように注意してください。カスタムロジックがキューから要素を取り出す順序を直接決定するため、その動作をしっかり理解することが重要です。
PHP SplPriorityQueue でカスタム比較処理を実装する
1<?php 2 3/** 4 * SplPriorityQueue を継承し、独自の優先度比較ロジックを持つキューを定義します。 5 * 6 * SplPriorityQueue のデフォルトの動作では、数値が大きいほど「高優先度」とみなされます。 7 * このクラスでは、compare メソッドをオーバーライドすることで、 8 * 「数値が小さいほど高優先度」というカスタムロジックを実装します。 9 */ 10class CustomPriorityQueue extends SplPriorityQueue 11{ 12 /** 13 * 2つの優先度を比較し、キュー内での要素の順序を決定します。 14 * 15 * このメソッドの戻り値によって、どちらの優先度がより高いかが決まります。 16 * 17 * @param mixed $priority1 比較する最初の優先度。 18 * @param mixed $priority2 比較する2番目の優先度。 19 * @return int 比較結果を示す整数値。 20 * - 正の整数: $priority1 が $priority2 よりも「高優先度」と判断される場合。 21 * - 0: $priority1 と $priority2 の優先度が等しい場合。 22 * - 負の整数: $priority1 が $priority2 よりも「低優先度」と判断される場合。 23 */ 24 public function compare(mixed $priority1, mixed $priority2): int 25 { 26 // ここでは、「数値が小さいほど高優先度」とするロジックを実装します。 27 // これは SplPriorityQueue のデフォルトの比較動作(大きいほど高優先度)とは逆になります。 28 // 29 // 宇宙船演算子 (spaceship operator <=>): 30 // - $a < $b の場合、-1 を返します。 31 // - $a == $b の場合、0 を返します。 32 // - $a > $b の場合、1 を返します。 33 // 34 // 例: 35 // priority1 = 1, priority2 = 5 の場合: 36 // $priority2 <=> $priority1 は 5 <=> 1 となり、1 を返します。 37 // これは「priority1 (1) の方が priority2 (5) よりも優先度が高い」と判断されます。 38 // 39 // priority1 = 5, priority2 = 1 の場合: 40 // $priority2 <=> $priority1 は 1 <=> 5 となり、-1 を返します。 41 // これは「priority1 (5) の方が priority2 (1) よりも優先度が低い」と判断されます。 42 return $priority2 <=> $priority1; 43 } 44} 45 46// --- CustomPriorityQueue の使用例 --- 47echo "--- カスタム優先度キューのデモンストレーション ---\n\n"; 48 49$queue = new CustomPriorityQueue(); 50 51// 要素とそれに対応する優先度(数値が小さいほど高優先度)を追加します。 52$queue->insert('緊急タスク', 1); 53$queue->insert('通常タスクA', 5); 54$queue->insert('通常タスクB', 3); 55$queue->insert('低優先度タスク', 10); 56$queue->insert('追加タスク', 2); 57 58echo "キューに追加されたタスクの優先度:\n"; 59echo " - 緊急タスク (優先度: 1)\n"; 60echo " - 通常タスクA (優先度: 5)\n"; 61echo " - 通常タスクB (優先度: 3)\n"; 62echo " - 低優先度タスク (優先度: 10)\n"; 63echo " - 追加タスク (優先度: 2)\n\n"; 64 65echo "キューから要素を優先度順 (数値が小さい順) に取り出します:\n"; 66 67// キューが空になるまで、最も優先度の高い(数値が小さい)要素を取り出します。 68while (!$queue->isEmpty()) { 69 $task = $queue->extract(); // 最も優先度の高い要素を取得 70 echo "- " . $task . "\n"; 71} 72 73echo "\n--- デモンストレーション終了 ---\n"; 74
PHPのSplPriorityQueueは、要素を優先度に基づいて管理する特殊なキューです。このキューに追加された要素は、設定された優先度に従って自動的に並び替えられ、最も優先度の高い要素から順に取り出すことができます。
SplPriorityQueueクラスに定義されているcompareメソッドは、2つの優先度を比較し、どちらがより高いかを判断するためのロジックを提供します。このメソッドは通常、キューの内部で自動的に呼び出されますが、SplPriorityQueueを継承したクラスでこのメソッドをオーバーライドすることで、独自の優先度比較ルールを実装できます。
引数$priority1と$priority2は、比較対象となる2つの優先度をそれぞれ受け取ります。戻り値のintは、比較結果を示す整数値です。もし$priority1が$priority2よりも「高優先度」と判断される場合は正の整数を、両者の優先度が等しい場合は0を、$priority1が「低優先度」と判断される場合は負の整数を返します。
サンプルコードでは、CustomPriorityQueueクラスがSplPriorityQueueを継承し、compareメソッドをオーバーライドしています。ここでは、デフォルトの「数値が大きいほど高優先度」という動作を「数値が小さいほど高優先度」となるように変更しています。具体的には、$priority2 <=> $priority1という宇宙船演算子を使用することで、$priority1が小さいほど、比較結果が正の整数となり、$priority1が高優先度であると判断されるようにロジックを反転させています。これにより、このカスタムキューでは、設定した優先度(数値)が小さいタスクから順に取り出されるようになります。
SplPriorityQueueのcompareメソッドは、要素の優先度を決定する重要な部分です。このメソッドは、$priority1が$priority2よりも高優先度と判断される場合に正の整数、等しい場合にゼロ、低優先度と判断される場合に負の整数を返す必要があります。デフォルトの比較動作(数値が大きいほど高優先度)とは逆に、サンプルコードでは$priority2 <=> $priority1とすることで、数値が小さいほど高優先度となるカスタムロジックを実装しています。この戻り値のルールと、デフォルトの動作からの変更点を正しく理解しないと、キューから要素が意図しない順序で取り出される原因となりますのでご注意ください。また、比較対象となる優先度のデータ型は一貫させ、予期せぬ挙動を避けるようにしてください。