ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
配列を返す場合との違い
// 配列を作って返す: 100 万件ぶんのメモリが必要
function rangeArray(int $n): array
{
$result = [];
for ($i = 0; $i < $n; $i++) {
$result[] = $i;
}
return $result;
}
// ジェネレータ: 1 件ずつ作る
function rangeGen(int $n): Generator
{
for ($i = 0; $i < $n; $i++) {
yield $i;
}
}
foreach (rangeGen(1_000_000) as $i) {
if ($i > 3) break;
echo $i; // 0 1 2 3 4 件目以降は作られない
}
$before = memory_get_usage();
$a = rangeArray(1_000_000);
echo (memory_get_usage() - $before) / 1024 / 1024; // 数十 MB
$before = memory_get_usage();
$g = rangeGen(1_000_000);
echo (memory_get_usage() - $before); // ほぼ 0
呼んだ時点では実行されない
function gen(): Generator
{
echo "開始\n";
yield 1;
echo "途中\n";
yield 2;
echo "終了\n";
}
$g = gen(); // 何も出力されない(Generator を作っただけ)
echo "作成した\n";
foreach ($g as $v) { // ここで初めて中身が動く
echo "受け取り: {$v}\n";
}
// 作成した / 開始 / 受け取り: 1 / 途中 / 受け取り: 2 / 終了
yield のところで実行が一時停止し、次の値が要求されたときに続きから再開します。この「途中で止まる」性質がジェネレータの本質です。
大きなファイルを読む
function readLines(string $path): Generator
{
$fp = fopen($path, 'r');
if ($fp === false) {
throw new RuntimeException("開けません: {$path}");
}
try {
while (($line = fgets($fp)) !== false) {
yield rtrim($line, "\r\n");
}
} finally {
fclose($fp); // 途中で break しても必ず閉じる
}
}
foreach (readLines('huge.csv') as $i => $line) {
if ($i === 0) continue; // ヘッダーを飛ばす
// 1 行ずつ処理する
}
file() や file_get_contents() はファイル全体をメモリに載せます。数 GB の CSV では Allowed memory size exhausted になるため、この形で 1 行ずつ処理します。finally を付けておくと、途中で break してもファイルが閉じられます。
キー付きの yield
function pairs(): Generator
{
yield 'name' => '田中';
yield 'age' => 30;
}
foreach (pairs() as $key => $value) {
echo "{$key}: {$value}\n";
}
// キーを省略すると 0 から自動採番される
function nums(): Generator
{
yield 'a'; // キー 0
yield 'b'; // キー 1
yield 5 => 'c'; // キー 5
yield 'd'; // キー 6
}
yield from で繋げる
function inner(): Generator
{
yield 1;
yield 2;
return 'inner の戻り値';
}
function outer(): Generator
{
yield 0;
$result = yield from inner(); // inner の値をそのまま流す
yield 3;
echo $result; // inner の戻り値
}
foreach (outer() as $v) { echo $v; } // 0 1 2 3
// 配列も流せる
function withArray(): Generator
{
yield from [10, 20];
yield 30;
}
yield from はキーをそのまま引き継ぎます。複数のジェネレータを繋げるとキーが重複するため、iterator_to_array() するときは第 2 引数を false にしてキーを捨ててください。
戻り値と send()
function counter(): Generator
{
$count = 0;
while (true) {
$add = yield $count; // send() で渡された値を受け取る
if ($add === null) break;
$count += $add;
}
return $count; // getReturn() で取れる
}
$g = counter();
echo $g->current(); // 0
echo $g->send(5); // 5
echo $g->send(3); // 8
$g->send(null); // ループを抜ける
echo $g->getReturn(); // 8
| メソッド | 働き |
|---|---|
current() | いまの値を返す(進めない) |
key() | いまのキー |
next() | 次まで進める |
valid() | まだ値があるか |
send($v) | 値を渡して次まで進め、その値を返す |
getReturn() | 最後まで回したあとに return の値を取る |
getReturn() を途中で呼ぶと Exception: Cannot get return value of a generator that hasn't returned になります。
制約と注意点
$g = rangeGen(3);
// count() は使えない(Countable ではない)
// echo count($g); // TypeError
echo iterator_count(rangeGen(3)); // 3 ただし全部消費する
// 添字アクセスもできない
// echo $g[0]; // Error
// 一度回すと再利用できない
foreach ($g as $v) {}
foreach ($g as $v) { echo $v; } // Exception: Cannot traverse an already closed generator
// 2 回使いたいなら配列にする(メモリの利点は失われる)
$array = iterator_to_array(rangeGen(3));
// 途中で巻き戻すこともできない
// $g->rewind(); // 開始後は Exception
Generator を返す関数の型宣言
function gen1(): Generator { yield 1; } // 具体的
function gen2(): iterable { yield 1; } // 配列でもジェネレータでもよい
function total(iterable $rows): int // 受け取る側は iterable にしておくと柔軟
{
$sum = 0;
foreach ($rows as $r) { $sum += $r; }
return $sum;
}
echo total([1, 2, 3]); // 6
echo total(rangeGen(4)); // 6
引数の型は array ではなく iterable にしておくと、配列とジェネレータの両方を受け取れます。
使いどころのまとめ
| 状況 | 選ぶもの |
|---|---|
| 件数が少なく、何度も使う | 配列 |
| 件数が多い / 不明(ファイル・DB・API のページ送り) | ジェネレータ |
| 途中で打ち切ることがある | ジェネレータ |
ソートや count() が必要 | 配列 |
| 無限に続く列(連番・繰り返し) | ジェネレータ |
関連
- 文法 — 親カテゴリ
- returnとyieldの違い
- 繰り返し処理
- 関数
- CSV読み込み
- Fatal error: Maximum execution time of 30 seconds exceeded in...
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページ
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- 【django】ログイン 認証機能 2026-09-08 03:22:09
- MySQL ERROR 1063 Incorrect column specifier for column|原因と直し方 2026-09-08 03:11:09
- 【PHPエラー】Object of class stdClass could not be converted to string 2026-09-07 07:46:04
- Julia Genie ローカル開発サーバ起動完全ガイド 2026-09-07 07:46:04
- Wi-Fi とは|規格と世代(Wi-Fi 4〜7)・周波数帯・CSMA/CA・WPA3 NEW 2026-09-07 07:45:13
- set コマンドでシェルオプションと位置パラメータを操作 | bash 2026-09-07 07:45:13
- JPEG(.jpg/.jpeg)画像形式の完全ガイド — 仕様・マジックナンバー・他形式との比較・EXIF 2026-09-07 07:45:13
- UE5 Get Overlapping Actorsで特定クラスだけ処理|Class Filter・Cast To 2026-09-07 07:45:13
- Linuxで特定拡張子のファイルを再帰削除|find -deleteの安全手順 2026-09-07 07:45:13
- Django CBVでテンプレートに値を渡す|get_context_data・extra_context 2026-09-07 07:45:13
- Linuxで複数ファイルの文字列を一括置換|find・sed・xargsの安全手順 2026-09-07 07:45:13
- Laravelルートグループ|prefix・middleware・nameで一括管理 2026-09-07 07:45:13
- Linux whichコマンドの使い方|絶対パス取得とtype・command -vの違い 2026-09-07 07:45:13
- Linux catコマンドの使い方|行番号表示・複数ファイル連結 2026-09-07 07:45:13
- unable to execute 'gcc': No such file or directory 2026-09-07 07:45:13
コメントを削除してもよろしいでしょうか?