【PHP8.x】FilterIterator::accept()メソッドの使い方
acceptメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
『acceptメソッドは、イテレータの現在の要素が有効かどうかを判定するフィルタリング条件を定義するためのメソッドです。このメソッドは、抽象クラスであるFilterIteratorに定義されており、このクラスを継承して独自のフィルタクラスを作成する際に必ず実装する必要があります。foreachループなどでイテレータを反復処理すると、各要素に対して内部的にこのacceptメソッドが自動的に呼び出されます。メソッド内では、現在の要素が目的の条件を満たしているかを判定するロジックを記述します。判定結果は真偽値(bool)で返し、trueを返した場合はその要素が有効とみなされ、イテレーションの結果に含まれます。逆にfalseを返した場合は、その要素は無効とみなされ、スキップされます。この仕組みを利用することで、例えば「偶数のみを抽出する」や「特定の文字列を含む要素のみを抽出する」といった、独自のフィルタリングルールを持つカスタムイテレータを容易に作成することができます。
構文(syntax)
1<?php 2 3// FilterIteratorを継承して、独自のフィルタクラスを定義します。 4// この例では、偶数のみを通過させるフィルタです。 5class EvenNumberFilter extends FilterIterator 6{ 7 /** 8 * このメソッドで、現在の要素がイテレーションに含まれるべきか判断します。 9 * 10 * @return bool trueを返すと現在の要素は有効、falseを返すと無効になります。 11 */ 12 public function accept(): bool 13 { 14 // 現在の要素が偶数であればtrueを返します。 15 return $this->current() % 2 === 0; 16 } 17} 18 19// フィルタリング対象の配列 20$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 21 22// 配列をイテレータに変換します。 23$iterator = new ArrayIterator($numbers); 24 25// 作成したフィルタクラスのインスタンスを生成し、イテレータを渡します。 26$filter = new EvenNumberFilter($iterator); 27 28// フィルタリングされた結果をforeachでループします。 29// accept() が true を返した要素だけが処理されます。 30foreach ($filter as $evenNumber) { 31 echo $evenNumber . "\n"; 32} 33 34?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
bool
FilterIterator::accept() メソッドは、現在の要素がフィルタリング基準を満たしているかどうかを示す真偽値(bool)を返します。true の場合は要素が保持され、false の場合はスキップされます。
サンプルコード
PHP FilterIteratorで受け入れテストに合格した機能のみを抽出する
1<?php 2 3declare(strict_types=1); 4 5/** 6 * 受け入れテストの対象となる機能を表現するシンプルなクラス 7 */ 8final class Feature 9{ 10 public function __construct( 11 public readonly string $name, 12 public readonly string $status // 'passed', 'failed', 'in_progress' 13 ) { 14 } 15} 16 17/** 18 * FilterIteratorを継承し、受け入れテスト(Acceptance Testing)に 19 * 合格した項目のみを抽出するカスタムイテレータ。 20 * 21 * FilterIteratorの核心は、このaccept()メソッドを実装することにあります。 22 */ 23final class AcceptanceTestPassedFilter extends FilterIterator 24{ 25 /** 26 * 現在の要素がフィルタ条件を満たすか(受け入れるか)を判定します。 27 * 28 * このメソッドはイテレータの各要素に対して自動的に呼び出されます。 29 * trueを返した要素だけが、foreachループなどの反復処理の対象となります。 30 * 31 * @return bool 現在の要素が受け入れ基準を満たす場合は true、それ以外は false 32 */ 33 public function accept(): bool 34 { 35 // イテレータが指している現在の要素(Featureオブジェクト)を取得します。 36 $feature = $this->current(); 37 38 // Featureオブジェクトのステータスが 'passed' の場合のみ「受け入れる」と判断し、 39 // trueを返します。これがフィルタリングの条件です。 40 return $feature->status === 'passed'; 41 } 42} 43 44// 1. テスト対象となる機能リストの元データを作成します。 45// ArrayIteratorは、配列をイテレータとして扱えるようにするクラスです。 46$features = new ArrayIterator([ 47 new Feature('ユーザーログイン機能', 'passed'), 48 new Feature('商品検索機能', 'passed'), 49 new Feature('決済連携機能', 'failed'), 50 new Feature('管理画面', 'in_progress'), 51]); 52 53// 2. 作成したカスタムフィルタを使って、元のイテレータをラップします。 54$passedFeaturesIterator = new AcceptanceTestPassedFilter($features); 55 56// 3. フィルタリングされたイテレータをループ処理します。 57// accept()メソッドがtrueを返した要素のみが出力されます。 58echo "受け入れテストに合格した機能一覧:\n"; 59foreach ($passedFeaturesIterator as $feature) { 60 echo "- " . $feature->name . "\n"; 61}
このサンプルコードは、PHPのFilterIteratorクラスを継承し、acceptメソッドを実装することで、データの中から特定の条件を満たす要素だけを効率的に抽出する方法を示しています。ここでは、受け入れテストの結果リストから「合格」した機能のみを絞り込む処理を例に解説します。
FilterIteratorの核心は、acceptメソッドにあります。このメソッドは引数を持たず、戻り値としてbool型(trueかfalse)を返します。イテレータが持つ各要素を順番に評価し、その要素を結果に含めるべきか(true)含めないべきか(false)を判定する役割を担います。
サンプルコードのAcceptanceTestPassedFilterクラスでは、acceptメソッド内で$this->current()を使って現在処理中のFeatureオブジェクトを取得します。次に、そのstatusプロパティが'passed'である場合にのみtrueを返します。このフィルタを適用したイテレータをforeachで処理すると、acceptメソッドがtrueを返した要素、つまり受け入れテストに合格した機能だけが取り出され、画面に出力されます。
FilterIteratorは、元のデータを変更することなく、条件に合う要素だけを抽出するためのクラスです。このクラスを継承して作るカスタムフィルタの核心はacceptメソッドの実装にあります。このメソッドがtrueを返した要素だけが、ループ処理の対象として残ります。注意点として、acceptメソッドはforeachループなどで反復処理を行う際に、各要素に対して自動的に呼び出されます。自分で直接呼び出すものではありません。また、安全に利用するためには、acceptメソッド内で$this->current()によって取得した要素が、期待するクラスのインスタンスであるかを確認することが重要です。もし予期しない型のデータが含まれていると、プロパティへのアクセスでエラーが発生する可能性があるためです。
PHP FilterIterator::acceptでPOST JSONをフィルタリングする
1<?php 2 3declare(strict_types=1); 4 5/** 6 * 'active'プロパティがtrueのオブジェクトのみを通過させるフィルタクラス。 7 * 8 * FilterIteratorを継承し、accept()メソッドを実装することで、 9 * イテレーション(繰り返し処理)中に要素をフィルタリングする独自のロジックを定義します。 10 */ 11class ActiveItemFilter extends FilterIterator 12{ 13 /** 14 * 現在の要素をイテレーションに含めるかどうかを決定します。 15 * 16 * このメソッドは、FilterIteratorによって要素が1つずつ渡されるたびに呼び出されます。 17 * trueを返すとその要素は残り、falseを返すと除外されます。 18 * 19 * @return bool 現在の要素が条件('active'がtrue)を満たす場合はtrue、それ以外はfalse。 20 */ 21 public function accept(): bool 22 { 23 // イテレータが指している現在の要素を取得します。 24 $item = $this->current(); 25 26 // 要素がオブジェクトであり、'active'プロパティが存在し、その値がtrueであるかを確認します。 27 return is_object($item) && isset($item->active) && $item->active === true; 28 } 29} 30 31// --- 以下、実行サンプルコード --- 32 33/** 34 * POSTリクエストで受け取ったJSONデータをフィルタリングする関数。 35 * 36 * @param string $jsonPostData POSTリクエストのボディとして受け取ったJSON文字列。 37 * @return string フィルタリング後の結果をJSON形式の文字列で返す。 38 */ 39function filterActiveItemsFromPost(string $jsonPostData): string 40{ 41 // JSONデータをPHPのオブジェクト配列にデコードします。 42 // 第2引数をfalseにするとオブジェクト、trueにすると連想配列になります。 43 $items = json_decode($jsonPostData); 44 45 // デコードに失敗した場合や、データが配列でない場合は空のJSON配列を返します。 46 if (!is_array($items)) { 47 return '[]'; 48 } 49 50 // PHPの配列を反復処理可能にするために、ArrayIteratorでラップします。 51 $iterator = new ArrayIterator($items); 52 53 // 作成したActiveItemFilterを使って、ArrayIteratorをフィルタリングします。 54 $filteredIterator = new ActiveItemFilter($iterator); 55 56 // フィルタリングされた結果を新しい配列に格納します。 57 // iterator_to_array() を使うと、ループ処理を簡潔に書けます。 58 $activeItems = iterator_to_array($filteredIterator); 59 60 // 結果を整形されたJSON文字列にエンコードして返します。 61 return json_encode(array_values($activeItems), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); 62} 63 64// --- 実行部分 --- 65 66// Web APIなどでPOSTリクエスト経由で受け取ったJSONデータをシミュレートします。 67$simulatedJsonPost = <<<JSON 68[ 69 {"id": 101, "name": "商品A", "active": true}, 70 {"id": 102, "name": "商品B", "active": false}, 71 {"id": 103, "name": "商品C", "active": true}, 72 {"id": 104, "name": "商品D", "active": true}, 73 {"id": 105, "name": "商品E (無効)", "active": false} 74] 75JSON; 76 77// 関数を呼び出して、フィルタリング処理を実行します。 78$filteredJsonResult = filterActiveItemsFromPost($simulatedJsonPost); 79 80// HTTPレスポンスヘッダを設定して、出力がJSONであることをクライアントに伝えます。 81// (コマンドラインで実行する場合はこの行は影響しません) 82header('Content-Type: application/json; charset=utf-8'); 83 84// フィルタリングされた結果を出力します。 85echo $filteredJsonResult; 86 87/* 88--- 期待される出力 --- 89[ 90 { 91 "id": 101, 92 "name": "商品A", 93 "active": true 94 }, 95 { 96 "id": 103, 97 "name": "商品C", 98 "active": true 99 }, 100 { 101 "id": 104, 102 "name": "商品D", 103 "active": true 104 } 105] 106*/
このPHPコードは、FilterIteratorクラスを継承し、そのacceptメソッドを実装することで、配列やオブジェクトの繰り返し処理中に特定の条件で要素をフィルタリングする方法を示しています。Web APIなどでPOSTリクエストにより受け取ったJSONデータを処理するような、実践的な場面を想定したサンプルです。
中心となるのはActiveItemFilterクラスに定義されたacceptメソッドです。このメソッドは、繰り返し処理対象の要素を1つずつ判定するために自動的に呼び出されます。acceptメソッドは引数を持たず、現在の要素が条件を満たすかどうかをbool型(trueまたはfalse)の戻り値で返します。trueを返すとその要素は結果に残り、falseを返すと除外されます。
このサンプルでは、POSTされたJSONデータをオブジェクトの配列に変換した後、activeプロパティがtrueである要素のみを通過させるフィルタとしてacceptメソッドを実装しています。これにより、有効なデータだけを効率的に抽出し、その結果を再びJSON形式で出力することができます。
このコードは、FilterIteratorを継承し、acceptメソッドに独自の判定ロジックを実装する良い例です。acceptメソッドがtrueを返した要素だけが、繰り返し処理の結果として残ります。注意点として、json_decodeはデフォルトでデータをオブジェクトに変換するため、$item->activeのようにアロー演算子でアクセスします。もし連想配列として扱いたい場合は、json_decode($json, true)と指定し、$item['active']のようにアクセスする必要があります。また、フィルタリング後の結果にarray_valuesを適用しているのは、元の配列のキーが維持されて歯抜け状態になるのを防ぎ、JSONで期待通りの配列[]として出力するための重要な処理です。この一手間が、意図しないJSONオブジェクト{}の生成を防ぎます。