【PHP】 yieldとは?PHPのジェネレーターでメモリ効率を劇的に改善する方法を解説!

PHP
Eslo
Eslo

PHPの「yield」を使ったジェネレーター関数をご存じですか?この記事では、ジェネレーター関数を使用した場合のメリットとその使い方を、具体的なコード例を交えて詳しく解説します。大規模なデータを扱う際のパフォーマンス改善にも繋がるため、ぜひ参考にしてみてください!

yieldとは?ジェネレーターの基本を理解しよう!

「yield」はPHPで使用されるキーワードで、ジェネレーターを構築する際に利用します。ジェネレーターは、通常のようにすべての処理結果を一度に返すのではなく、処理の一部を順次返します
例えば、大量のデータを扱う場合において、通常の配列を使用すると全データをメモリに格納しますが、ジェネレーターを使えば、必要なデータを1つずつ生成するため、メモリ効率が大幅に向上します。

PHP: ジェネレータとは - Manual
PHP is a popular general-purpose scripting language that powers everything from your blog to the most popular websites i...

ジェネレーターを使ってみよう!

通常は、returnを使って処理結果を一度に返します。一方、ジェネレーターではyieldを使い、処理結果を1つずつ返す仕組みです。
以下のコード例で違いを見てみましょう。

通常の場合:

foreach (range(1, 10000) as $val) {
    echo $val;
}

上記のコードでは、range()関数が1から10,000までの配列を一括で生成するため、その分メモリを消費します。大規模なデータになるほどメモリ負荷が増加します。

ジェネレーターの場合:

function countNum($limit) {
    for ($i = 1; $i <= $limit; ++$i) {
        yield $i;
    }
}
foreach (countNum(10000) as $val) {
    echo $val;
}

ジェネレーターを使うと、yieldで値を1つずつ生成するため、配列全体をメモリに格納する必要がありません。この仕組みにより、メモリ使用量を大幅に削減できます。

実用例:ジェネレーター関数の活用シーン

1.ファイルの逐次読み込み

大きなファイルを1行ずつ読み込む場合、ジェネレーター関数を使用することで効率的に処理できます。

    function readLargeFile($filePath) {
        $handle = fopen($filePath, 'r');
        if ($handle) {
            while (($line = fgets($handle)) !== false) {
                yield $line;
            }
            fclose($handle);
        }
    }
    foreach (readLargeFile('large_file.txt') as $line) {
        echo $line;
    }

    2.データベースクエリの結果を逐次処理

    データベースから取得した大量のレコードを1件ずつ処理する場合にも適しています。

    function fetchRows($pdo, $query) {
        $stmt = $pdo->query($query);
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            yield $row;
        }
    }
    foreach (fetchRows($pdo, 'SELECT * FROM large_table') as $row) {
        print_r($row);
    }

    まとめ:yieldで効率的なデータ処理を!

    PHPの「yield」を使ったジェネレーター関数は、大規模なデータを扱う際にメモリ効率を改善し、処理速度を向上させる非常に便利な機能です。特に、ファイル処理やデータベース操作など、逐次処理が求められるシーンで力を発揮します。この記事で紹介した例を参考に、ぜひ実際のプロジェクトで活用してみてください!