本日、PHPチームは PHP 5.5.0 バージョンをリリースしました。 generators。Reading ドキュメント 、I配列でできることを正確に実行することに気づきました。
PHPチームジェネレーター例:
// Only PHP 5.5
function gen_one_to_three() {
for ($i = 1; $i <= 3; $i++) {
// Note that $i is preserved between yields.
yield $i;
}
}
$generator = gen_one_to_three();
foreach ($generator as $value) {
echo "$value\n";
}
結果:
1
2
3
しかし、配列を使用して同じことを行うことができます。また、以前のバージョンのPHPとの互換性を維持できます。
見てください:
// Compatible with 4.4.9!
function gen_one_to_three() {
$results = array();
for ($i = 1; $i <= 3; $i++) {
$results[] = $i;
}
return $results;
}
$generator = gen_one_to_three();
foreach ($generator as $value) {
echo "$value\n";
}
それで問題は:この新機能の存在の目的は何ですか?新しい機能を使用せずに、ドキュメントのすべての例を再生して、配列に置き換えました。
誰かが良い説明とおそらく古いバージョンでは必ずしも不可能ではない例を与えることができますが、ジェネレーターを使用すると開発に役立ちますか?
違いは効率の点です。たとえば、PHP以外の多くの言語には2つのrange
関数range()
とxrange()
が含まれています。これはジェネレーターとその使用理由独自のジェネレーターを作成しましょう:
function range($start, $end) {
$array = array();
for ($i = $start; $i <= $end; $i++) {
$array[] = $i;
}
return $array;
}
今ではそれは本当に簡単です。ただし、範囲が広い場合は、膨大な量のメモリが必要になります。 $start = 0
と$end = 100000000
を使用して実行しようとすると、メモリが不足する可能性があります。
しかし、ジェネレーターを使用した場合:
function xrange($start, $end) {
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}
現在、定数メモリを使用していますが、同じスペースで反復できる(そして他のイテレータで使用できる)「配列」(構造のような)がまだあります。
配列を置換しませんが、メモリの必要性を回避する効率的な方法を提供します...
しかし、それはまた、アイテムの生成に関して節約を提供します。各結果は必要に応じて生成されるため、必要になるまで各要素の実行(フェッチまたは計算)を遅らせることができます。したがって、たとえば、データベースからアイテムをフェッチし、各行の周りで複雑な処理を行う必要がある場合、実際にその行が必要になるまで、ジェネレーターを使用してそれを遅らせることができます。
function fetchFromDb($result) {
while ($row = $result->fetchArray()) {
$record = doSomeComplexProcessing($row);
yield $record;
}
}
したがって、最初の3つの結果のみが必要な場合は、最初の3つのレコードのみを処理します。
詳細については、この正確な主題について ブログ投稿 を書きました。
ジェネレーターは、複雑なステートメントの遅延評価を可能にします。そうすれば、すべてを一度に割り当てる必要がないため、メモリを節約できます。
両方が反復可能であることに加えて、それらはほとんど同じではありません。 array
はデータ構造ですが、ジェネレーターはそうではありません。
配列には、ループを開始する前に、ループしている各値が含まれている必要があります。ジェネレータは、要求に応じて「オンザフライ」で各値を作成するため、メモリが大幅に削減されます。
配列は、含まれている値で機能し、それらの値を事前に入力する必要があります。ジェネレーターは、直接使用される特別な基準に従って値を作成できます...例:フィボナッチ数列、または非A-Zアルファベットの文字(UTF-8数値で計算)により、alphaRange( 'א'、 'ת');が効果的に許可されます。
[〜#〜]編集[〜#〜]
function fibonacci($count) {
$prev = 0;
$current = 1;
for ($i = 0; $i < $count; ++$i) {
yield $prev;
$next = $prev + $current;
$prev = $current;
$current = $next;
}
}
foreach (fibonacci(48) as $i => $value) {
echo $i , ' -> ' , $value, PHP_EOL;
}
[〜#〜]編集[〜#〜]
楽しみのために、ヘブライ語のアルファベットをUTF-8文字として返すジェネレーターを次に示します。
function hebrewAlphabet() {
$utf8firstCharacter = 1488;
$utf8lastCharacter = 1514;
for ($character = $utf8firstCharacter; $character <= $utf8lastCharacter; ++$character) {
yield html_entity_decode('&#'.$character.';', ENT_NOQUOTES, 'UTF-8');
};
}
foreach(hebrewAlphabet() as $character) {
echo $character, ' ';
}
Pythonの場合:
アイテムのセットに対する反復がforステートメントの使用を開始すると、ジェネレーターが実行されます。ジェネレーターの関数コードが「yield」ステートメントに達すると、ジェネレーターは実行をforループに戻し、セットから新しい値を返します。ジェネレーター関数は、必要な数の値(場合によっては無限)を生成して、それぞれを順番に生成できます。
...ジェネレーターはyieldステートメントを一度に1つずつ実行し、その間に一時停止して、実行をメインのforループに戻します。