この記事では、PHP のパフォーマンス最適化ツールである PHP ジェネレーターの詳細な説明を紹介します。一定の参考値があります。必要な友人は参照してください。お役に立てれば幸いです。
Python または他の言語で作業している場合は、ジェネレーターについてよく知っている必要があります。しかし、ジェネレーターは PHP 5.5.0 で導入された機能であるため、またはその機能があまり明確ではないため、ジェネレーター機能を知らない PHP 開発者も多いかもしれません。しかし、ジェネレーター機能は本当に便利です。
利点
コンセプトについて直接話すと、聞いてもまだ混乱すると思いますので、最初に利点について話しましょう。あなたの興味を呼び起こします。では、ジェネレーターの利点は次のとおりです。
ジェネレーターは、PHP アプリケーションのパフォーマンスに非常に大きな影響を与えます
PHP コードランタイム メモリを大量に節約する
大量のデータの計算に適しています
では、これらの魔法の機能はどのように実現されるのでしょうか?まず例を挙げてみましょう。
概念の紹介
まず、ジェネレーターの概念の重荷を脇に置いて、単純な PHP 関数を見てみましょう:
function createRange($number){ $data = []; for($i=0;$i<p> これは、非常に一般的な PHP 関数で、配列を処理するときによく使用されます。ここのコードも非常に単純です: </p><ol class=" list-paddingleft-2"> <li><p>関数を作成します。 </p></li> <li>#関数には <p>for<code> ループが含まれています。現在の時刻を </code>$data<code></code></p> </li># にループします。 <li>#for<p>ループが実行されると、<code>$data</code> が返されます。 <code></code></p> </li> まだ終わっていないので、続けましょう。別の関数を作成し、この関数の戻り値をループで出力してみましょう: </ol><pre class="brush:php;toolbar:false">$result = createRange(10); // 这里调用上面我们创建的函数 foreach($result as $value){ sleep(1);//这里停顿1秒,我们后续有用 echo $value.'<br>'; }
ブラウザで実行結果を見てみましょう:
##ここでは完璧です、何の問題もありません。 (もちろん sleep(1)
効果はわかりません)質問について考えてください
関数を呼び出したときに次のことに気づきました。 createRange
が渡されると、$number に渡される値は 10 であり、非常に小さな数値です。ここで値
10000000 (1000 万) を渡すとします。
次に、関数
createRange
for ループを
1000 回実行する必要があります。そして、
1000 百万個の値が
$data に配置され、
$data 配列がメモリに配置されます。したがって、関数を呼び出すときに多くのメモリが占有されます。
ここでジェネレーターがその才能を発揮します。
ジェネレーターを作成します
コードを直接変更します。注意してください:
function createRange($number){ for($i=0;$i今のコードとよく似ています。配列 <p>$data</p> を削除し、コンテンツは返されませんでしたが、<p>time()<code> ##Use の前にキーワード </code>yield<code></code><code># を使用しましたジェネレーター</code></p><p> コードの 2 番目の部分をもう一度実行してみましょう: <strong><pre class="brush:php;toolbar:false">$result = createRange(10); // 这里调用上面我们创建的函数 foreach($result as $value){ sleep(1); echo $value.'<br>'; }
奇跡的な発見、出力値は次のとおりです。ジェネレーターを使用しなかった最初の時とは異なります。ここでの値(タイムスタンプ)は 1 秒ごとに区切られています。 ここでの 1 秒間隔は、実際には
sleep(1)の結果です。しかし、なぜ最初はギャップがないのでしょうか?その理由:
ジェネレーターが使用されていない場合:
内の for
ループの結果関数はすぐに $ data
に配置され、すぐに戻ります。したがって、foreach
は固定配列をループします。
の値は一度にすぐには生成されず、foreach
ループに依存します。 foreach
は 1 回ループし、for
は 1 回実行します。
コード分析
コードを分析してみましょう。
function createRange($number){ for($i=0;$i'; }
コード実行プロセスを復元しましょう。
関数を呼び出し、パラメータ 10
を渡しますが、for
値は 1 回実行され、その後停止し、最初のループで使用できる値を foreach
に伝えます。
$result
でループを開始し、最初の sleep(1)
に来てから、使用を開始します for
で指定された値によって出力が実行されます。
は 2 番目のループを準備します。2 番目のループを開始する前に、再度 for
ループを要求します。
ループが再び実行され、生成されたタイムスタンプが foreach
. に伝えられます。
foreach
拿到第二个值,并且输出。由于foreach
中sleep(1)
,所以,for
循环延迟了1秒生成当前时间
所以,整个代码执行中,始终只有一个记录值参与循环,内存中也只有一条信息。
无论开始传入的$number
有多大,由于并不会立即生成所有结果集,所以内存始终是一条循环的值。
概念理解
到这里,你应该已经大概理解什么是生成器了。下面我们来说下生成器原理。
首先明确一个概念:生成器yield关键字不是返回值,他的专业术语叫产出值,只是生成一个值
那么代码中foreach
循环的是什么?其实是PHP在使用生成器的时候,会返回一个Generator
类的对象。foreach
可以对该对象进行迭代,每一次迭代,PHP会通过Generator
实例计算出下一次需要迭代的值。这样foreach
就知道下一次需要迭代的值了。
而且,在运行中for
循环执行后,会立即停止。等待foreach
下次循环时候再次和for
索要下次的值的时候,for
循环才会再执行一次,然后立即再次停止。直到不满足条件不执行结束。
实际开发应用
很多PHP开发者不了解生成器,其实主要是不了解应用领域。那么,生成器在实际开发中有哪些应用?
读取超大文件
PHP开发很多时候都要读取大文件,比如csv文件、text文件,或者一些日志文件。这些文件如果很大,比如5个G。这时,直接一次性把所有的内容读取到内存中计算不太现实。
这里生成器就可以派上用场啦。简单看个例子:读取text文件
我们创建一个text文本文档,并在其中输入几行文字,示范读取。
<?php header("content-type:text/html;charset=utf-8"); function readTxt() { # code... $handle = fopen("./test.txt", 'rb'); while (feof($handle)===false) { # code... yield fgets($handle); } fclose($handle); } foreach (readTxt() as $key => $value) { # code... echo $value.'<br>'; }
通过上图的输出结果我们可以看出代码完全正常。
但是,背后的代码执行规则却一点儿也不一样。使用生成器读取文件,第一次读取了第一行,第二次读取了第二行,以此类推,每次被加载到内存中的文字只有一行,大大的减小了内存的使用。
这样,即使读取上G的文本也不用担心,完全可以像读取很小文件一样编写代码。
相关文章推荐:
PHP7中生成器的新特性:生成器委托( yield-from )&返回值(return-value)
以上がPHPのパフォーマンス最適化ツール:PHPジェネレーターの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。