PHPジェネレーター
こんな状況に直面したことはありませんか?
これは、実行中のプロセスが許可されたRAMメモリ制限を超えてメモリを消費する場合に、PHP開発者が遭遇する可能性のあるエラーです。
具体的な例を見てみましょう:
private function range() { $a = []; for ($i = 0; $i < PHP_INT_MAX; $i++) { $a[] = $i; } return $a; } foreach ($this->range() as $value) { echo $value; }
上記のコードは、0からPHP_INT_MAX(現在のPHPバージョンが提供する最大の整数値)までの配列を作成し、その値を画面に出力します。コードを実行すると、先に述べたエラーが発生します。
このエラーに対処する方法はどうすれば良いのでしょうか?一つの方法は、“memory_limit”の設定をphp.iniファイルで増加させることです。
; スクリプトが消費する最大メモリ量 ; https://php.net/memory-limit memory_limit = 128M
しかし、これは最適な解決策ではありません。小さなコードでメモリ制限オーバーエラーが発生しているのは問題があります。そこで、メモリ制限を増加させる代わりに、PHPジェネレーターを使用して、どのようにメモリ使用量を削減できるか試してみましょう。
PHPジェネレーターとは?
PHPジェネレーターは、PHP 5.5で導入された強力な機能です。この機能により、ジェネレーター関数を作成することができ、ジェネレーター関数はすべての値を一度に返すのではなく、必要に応じて1つずつ値を生成して返します。これによりメモリを大幅に節約でき、データセット全体をメモリに保持せずにデータを処理することができます。
PHPジェネレーターの使用方法
上記のコードで、“range()”関数を変更して、配列(文字列)を作成してすべての値を返すのではなく、yieldキーワードを使って値を順番に返すようにします。簡単に言うと、yieldは値を返しますが、すべての値をメモリに保存することなく、その時点で呼び出すときにのみ値を返します。このようにすると、関数はジェネレーター関数になります。
private function range() { for ($i = 0; $i < PHP_INT_MAX; $i++) { yield $i; } } foreach ($this->range() as $value) { echo $value; }
PHPジェネレーターのメソッド
public current(): mixed public getReturn(): mixed public key(): mixed public next(): void public rewind(): void public send(mixed $value): mixed public throw(Throwable $exception): mixed public valid(): bool public __wakeup(): void
動作の例
別の例を試してみましょう:
function myGeneratorFunction() { echo 'One' . "<br>"; yield 'first return value' . "<br>"; echo 'Two' . "<br>"; yield 'second return value' . "<br>"; echo 'my return value' ; } $iterator = myGeneratorFunction(); $firstValue = $iterator->current(); echo $firstValue; $iterator->next(); $secondValue = $iterator->current(); echo $secondValue; $iterator->next(); echo $iterator->getReturn();
Output
One first return value Two second return value my return value
呼び出すと、$iterator->current()関数が実行され、“One”という値が表示され、最初のyieldキーワードで停止します。最初のyieldの値が返され、$firstValueに格納されます。
次に、$iterator->next();を呼び出すと、ジェネレーター関数は、最初のyieldで停止した位置から実行を再開します。この時、“Two”が表示され、2番目のyieldキーワードの値が返され、$secondValueに格納されます。次に、$iterator->next();を再度呼び出し、$iterator->getReturn();を使用して返された値を取得します。
この例から、yieldキーワードは関数を一時停止するように働き、yieldを呼び出すたびに関数は停止し、$iterator->next()を呼び出すことで続行されます。
キーの返却
yieldを使用してkey⇒valueを返す
private function range() { for ($i = 0; $i < PHP_INT_MAX; $i++) { yield "key {$i}" => "value {$i}"; } } foreach ($this->rangeKeyValue() as $key => $value) { echo "{$key} -> {$value} <br>"; }
Output
key 0 -> value 0 key 1 -> value 1 key 2 -> value 2 key 3 -> value 3 key 4 -> value 4 key 5 -> value 5 …
ジェネレーターへの引数の渡し方
引数をジェネレーターに渡して、関数を停止するようにすることもできます。方法は以下の通りです:
private function range() { for ($i = 0; $i < PHP_INT_MAX; $i++) { $value = yield $i; if ($value === 'stop') { return; } } } $generator = $this->range(); foreach ($generator as $value) { if ($value === 5) { $generator->send('stop'); } echo "current value is {$value} <br>"; }
Output
current value is 0 current value is 1 current value is 2 current value is 3 current value is 4 current value is 5
PHPジェネレーターの利点
アプリケーションが数ギガバイトのログファイルをデータベースに保存する必要がある場合、そのすべてを一度に読み込んで処理することはメモリオーバーフローを引き起こします。PHPジェネレーターを使用して、ログファイルの各行を逐次的に読み込んで処理することで、メモリの使用量を最小限に抑え、システムリソースを無駄に消費することなく、効率的に処理できます。
結論
大量のデータを処理する必要があるシステムでは、安全で最適な方法を選択することが非常に重要です。PHPジェネレーターは、メモリを節約し、サーバーの安定性とパフォーマンスを向上させる強力な解決策を提供します。システムの過負荷によるエラーを回避し、ユーザー体験の中断を防ぐためにも、PHPジェネレーターの使用を検討することが望ましいです。
![]() | Huỳnh Hữu Phát Web Developer |