【PHP8.x】iterator_to_array関数の使い方

作成日: 更新日:

iterator_to_array関数は、指定されたイテレーターからすべての要素を取り出し、新しい配列を作成して返す関数です。

イテレーターとは、データセットの要素を一つずつ順番に処理するための仕組みで、例えばforeachループで繰り返し処理ができるようなオブジェクトのことです。この関数を利用することで、イテレーターが提供するデータを一度にまとめてPHPの配列として扱うことができるようになります。

第一引数には、配列に変換したいイテレーターオブジェクトを指定します。第二引数はオプションで、変換後の配列のキーをどのように扱うかをbool型で指定します。この引数がtrueに設定されている場合、元のイテレーターのキーがそのまま配列のキーとして保持されます。デフォルト値はfalseで、この場合は数値キーが自動的に再割り当てされます。

iterator_to_array関数は、イテレーターの柔軟な反復処理能力と、PHPの豊富な配列操作関数(array_maparray_filterなど)の利便性を組み合わせたい場合に非常に有用です。例えば、データベースの結果セットやファイルから読み込んだデータを、一度に配列として扱って集計や加工を行いたい場合などに活用できます。

ただし、イテレーターが非常に多くの要素を持つ場合、この関数はすべての要素を一度にメモリにロードするため、大量のメモリを消費する可能性があります。そのため、処理するデータ量が多い場合には、メモリ使用量に注意して利用することが重要です。

基本的な使い方

構文(syntax)

<?php
$array = iterator_to_array($iterator, $preserve_keys);
?>

引数(parameters)

Traversable $iterator, bool $preserve_keys = true

  • Traversable $iterator: 配列に変換したいイテラブルなオブジェクトを指定します。
  • bool $preserve_keys = true: trueの場合、元のイテレータのキーを保持します。falseの場合、キーは再採番されます。

戻り値(return)

array

iterable を配列に変換したものを返します。

サンプルコード

PHPでイテレータを配列に変換する

<?php

/**
 * PHPのイテレータを配列に変換する `iterator_to_array` 関数の使用例です。
 *
 * この関数は、`Traversable` インターフェースを実装したオブジェクト(イテレータ)を
 * 通常のPHPの配列に変換します。
 */
function convertIteratorToArrayExample(): void
{
    // イテレータの元となる連想配列データを用意
    $data = [
        'apple' => 10,
        'banana' => 20,
        'orange' => 30,
    ];

    echo "--- 元データ ---\n";
    print_r($data);

    // ArrayIterator は Traversable インターフェースを実装しているため、
    // iterator_to_array 関数の引数として使用できます。
    $iterator = new ArrayIterator($data);

    echo "\n--- iterator_to_array の使用結果 ---\n";

    // ケース1: キーを保持してイテレータを配列に変換する (デフォルト動作)
    // 第二引数 $preserve_keys が true の場合、元のイテレータのキーが保持されます。
    // true はデフォルト値なので省略も可能です。
    echo "[1] キーを保持して配列に変換 (preserve_keys = true):\n";
    $arrayWithPreservedKeys = iterator_to_array($iterator, true);
    print_r($arrayWithPreservedKeys);
    // 出力例:
    // Array
    // (
    //     [apple] => 10
    //     [banana] => 20
    //     [orange] => 30
    // )

    // iterator_to_array はイテレータを最後まで走査します。
    // 同じイテレータで再度変換を行う場合は、rewind() を呼び出すか
    // 新しいイテレータを作成する必要があります。ここでは新しいイテレータを作成します。
    $iterator = new ArrayIterator($data);

    // ケース2: キーを再インデックスしてイテレータを配列に変換する
    // 第二引数 $preserve_keys が false の場合、キーは0から始まる数値キーに再インデックスされます。
    echo "\n[2] キーを再インデックスして配列に変換 (preserve_keys = false):\n";
    $arrayWithoutPreservedKeys = iterator_to_array($iterator, false);
    print_r($arrayWithoutPreservedKeys);
    // 出力例:
    // Array
    // (
    //     [0] => 10
    //     [1] => 20
    //     [2] => 30
    // )
}

// 関数を実行し、動作を確認します。
convertIteratorToArrayExample();

?>

PHPのiterator_to_array関数は、イテレータと呼ばれる特殊なオブジェクトを通常のPHPの配列に変換するために使用されます。イテレータとは、Traversableインターフェースを実装したオブジェクトのことで、データ集合を順に処理する仕組みを提供します。

この関数は、最初の引数に変換したいイテレータオブジェクトを受け取ります。そして、戻り値として、イテレータから変換された新しい配列を返します。

2番目の引数$preserve_keysは、変換時に元のイテレータのキーを保持するかどうかを決定する真偽値です。 true(デフォルト値)を指定すると、元のイテレータのキーがそのまま配列のキーとして利用されます。サンプルコードの最初の例のように、連想配列のキー('apple', 'banana'など)がそのまま維持されます。 一方、falseを指定すると、配列のキーは0から始まる連続した数値に再インデックスされます。サンプルコードの2番目の例では、キーが0, 1, 2...と数値に振り直されていることが確認できます。

サンプルコードでは、ArrayIteratorという、配列をイテレータとして扱うクラスを使用し、iterator_to_array関数の挙動を具体的に示しています。イテレータは一度最後まで走査されると、再度変換を行う場合は先頭に戻すか、新しいイテレータを作成する必要があるため、2番目の例では新しいArrayIteratorを生成しています。この関数を使うことで、イテレータで提供されるデータを配列として手軽に扱えるようになります。

iterator_to_array関数を使用すると、対象のイテレータは内部的に最後まで処理されます。そのため、一度この関数で変換したイテレータを再度利用しようとしても、中身が空の配列が返ってきてしまいます。もう一度変換したい場合は、サンプルコードのようにイテレータを新しく作り直すか、rewind()メソッドでポインタを先頭に戻す必要があります。第二引数は、省略すると元のキーが維持されますが、falseを明示的に指定するとキーが0から始まる連番に置き換わる点にも注意してください。巨大なデータを扱うイテレータを変換すると、メモリを大量に消費する可能性があるため、本当に配列への変換が必要な場面での利用が推奨されます。

PHP iterator_to_array で再帰ディレクトリを配列化する

<?php

/**
 * recursive iterator_to_array の使用例
 *
 * このスクリプトは、RecursiveDirectoryIterator と RecursiveIteratorIterator を使用して
 * ディレクトリを再帰的に走査し、その結果を iterator_to_array 関数で配列に変換する方法を示します。
 *
 * 1. テスト用のディレクトリ構造を作成します。
 * 2. RecursiveDirectoryIterator でディレクトリを再帰的に走査するイテレータを作成します。
 * 3. RecursiveIteratorIterator でこの再帰イテレータをフラット化し、葉(ファイル)のみを取得します。
 * 4. iterator_to_array を使用して、イテレータの内容を通常の配列に変換します。
 * 5. 結果を表示し、作成したテストデータをクリーンアップします。
 */

// --- 1. テスト用のディレクトリ構造を作成 ---
$testDir = 'temp_recursive_data';
$subDir = $testDir . DIRECTORY_SEPARATOR . 'subdir';

if (!is_dir($subDir)) {
    mkdir($subDir, 0777, true);
}

file_put_contents($testDir . DIRECTORY_SEPARATOR . 'file1.txt', 'Content of file1');
file_put_contents($subDir . DIRECTORY_SEPARATOR . 'file2.txt', 'Content of file2');
file_put_contents($subDir . DIRECTORY_SEPARATOR . 'file3.log', 'Content of file3');

echo "--- テストデータ作成完了 ---\n";

// --- 2. RecursiveDirectoryIterator と RecursiveIteratorIterator を使用して再帰的なイテレータを作成 ---
// RecursiveDirectoryIterator は指定されたディレクトリのイテレータを作成します。
// SKIP_DOTS フラグは . と .. をスキップします。
$directoryIterator = new RecursiveDirectoryIterator(
    $testDir,
    RecursiveDirectoryIterator::SKIP_DOTS
);

// RecursiveIteratorIterator は、RecursiveIterator からの再帰的なイテレーションをフラット化します。
// LEAVES_ONLY フラグは、イテレーションの「葉」要素(この場合はファイル)のみを返します。
$recursiveIterator = new RecursiveIteratorIterator(
    $directoryIterator,
    RecursiveIteratorIterator::LEAVES_ONLY
);

echo "--- iterator_to_array を使用して再帰イテレータを配列に変換 --- \n";

// --- 3. iterator_to_array を使用してイテレータの内容を配列に変換 ---
// 第1引数に Traversable オブジェクト (RecursiveIteratorIterator) を渡します。
// 第2引数 $preserve_keys はデフォルトで true なので、ここでは省略しています。
// この場合、ファイルパスが配列の要素となり、数値インデックスが割り当てられます。
$filesArray = iterator_to_array($recursiveIterator);

// --- 4. 結果を表示 ---
echo "取得されたファイルリスト:\n";
foreach ($filesArray as $path) {
    echo $path . "\n";
}
echo "\n";

echo "--- 変換された配列の内容 (var_dump) ---\n";
var_dump($filesArray);
echo "\n";

// --- 5. クリーンアップ ---
function rrmdir(string $dir): void
{
    if (!file_exists($dir)) {
        return;
    }
    $objects = scandir($dir);
    foreach ($objects as $object) {
        if ($object !== '.' && $object !== '..') {
            if (is_dir($dir . DIRECTORY_SEPARATOR . $object)) {
                rrmdir($dir . DIRECTORY_SEPARATOR . $object);
            } else {
                unlink($dir . DIRECTORY_SEPARATOR . $object);
            }
        }
    }
    rmdir($dir);
}

rrmdir($testDir);
echo "--- テストデータクリーンアップ完了 ---\n";

?>

iterator_to_arrayはPHP 8.4の拡張機能の一つで、Traversableインターフェースを実装したイテレータオブジェクトの内容を、通常のPHP配列に効率的に変換する関数です。

第一引数$iteratorには、配列に変換したいイテレータ(例: RecursiveIteratorIteratorなど)を指定します。このイテレータは、内部的に要素を順に取得できるオブジェクトである必要があります。 第二引数$preserve_keysはオプションで、デフォルト値はtrueです。この引数をtrueに設定すると、イテレータが現在指している要素のキーがそのまま変換後の配列のキーとして使用されます。falseに設定すると、新しい数値インデックスが0から順に割り当てられます。 戻り値は、イテレータの全ての要素を格納した新しいarrayです。

サンプルコードでは、RecursiveDirectoryIteratorRecursiveIteratorIteratorを組み合わせてディレクトリ内を再帰的に走査し、見つかったファイル(葉要素)のSplFileInfoオブジェクトを列挙するイテレータを作成しています。この再帰イテレータをiterator_to_array関数に渡すことで、取得されたSplFileInfoオブジェクトのリストが通常の配列としてまとめて取得されています。$preserve_keysがデフォルトのtrueであるため、イテレータが生成する数値インデックスとSplFileInfoオブジェクトが、そのまま配列のキーと値として格納されます。

iterator_to_arrayはイテレータの全要素を配列に変換するため、対象データ量が多いとメモリを大量消費する点にご注意ください。第2引数$preserve_keysはイテレータのキーを配列のキーとして保持するかを制御し、デフォルトはtrueです。この場合、イテレータのキー(サンプルではファイルパス)が配列のキーとして設定されます。また、配列の各要素はファイルパスの文字列ではなく、SplFileInfoオブジェクト自体であることにご留意ください。このオブジェクトはファイルの詳細情報を提供し、echoで表示する際にパス文字列へ変換されます。一度iterator_to_arrayを使用するとイテレータは最後まで走査されますので、再度利用する際はrewind()するか、新しいイテレータを生成してください。

【PHP8.x】iterator_to_array関数の使い方 | いっしー@Webエンジニア