在PHP中,收益率意味着什么?
我最近偶然发现了以下代码:在PHP中,收益率意味着什么?,php,generator,php-5.5,yield-keyword,Php,Generator,Php 5.5,Yield Keyword,我最近偶然发现了以下代码: function xrange($min, $max) { for ($i = $min; $i <= $max; $i++) { yield $i; } } 功能范围($min,$max) { 对于($i=$min;$i,收益率是多少? yield关键字 生成器函数的核心是yield关键字。在其最简单的形式中,yield语句看起来很像return语句,只是yield不是停止函数的执行并返回,而是向在生成器上循环的代码提供一个
function xrange($min, $max)
{
for ($i = $min; $i <= $max; $i++) {
yield $i;
}
}
功能范围($min,$max)
{
对于($i=$min;$i,收益率是多少?
yield
关键字
生成器函数的核心是yield关键字。在其最简单的形式中,yield语句看起来很像return语句,只是yield不是停止函数的执行并返回,而是向在生成器上循环的代码提供一个值并暂停生成器函数的执行
什么是发电机功能?
生成器函数实际上是一种更紧凑、更高效的编写函数的方法。它允许您定义一个函数(您的xrange
),该函数将在您执行以下操作时计算并返回值:
功能范围($min,$max){
对于($i=$min;$i$value){
echo“$key=>$value”,PHP_EOL;
}
这将创建以下输出:
0 => 1
1 => 2
…
9 => 10
您还可以使用控制foreach
中的$key
yield $someKey => $someValue;
在生成器函数中,$someKey
是您希望为$key
显示的任何值,$someValue
是$val
中的值。在问题示例中是$i
与正常功能有什么区别?
现在你可能想知道为什么我们不简单地使用PHP的本机来实现输出。你是对的。输出是一样的。区别在于我们是如何实现的
当我们使用range
PHP时,PHP将执行它,在内存中创建整个数字数组,然后将整个数组返回foreach
循环,循环将遍历它并输出值。换句话说,foreach
将对数组本身进行操作。range
函数和fo到达
只“交谈”一次。想象一下,这就像在邮件中收到一个包裹。送货员会把包裹递给你然后离开。然后你打开整个包裹,取出里面的任何东西
当我们使用生成器函数时,PHP将进入该函数并执行它,直到它满足end或yield
关键字。当它满足yield
时,它会将当时的值返回到外循环。然后它返回到生成器函数并从它产生的地方继续。因为我们的xrange
持有一个for
循环,它将执行并产生,直到达到$max
为止。想象一下它就像foreach
和打乒乓球的生成器一样
为什么我需要这个?
显然,生成器可以用来绕过内存限制。根据您的环境,执行范围(1000000)
将导致脚本死亡,而使用生成器执行相同操作则可以正常工作。或者,正如Wikipedia所说:
由于生成器仅根据需要计算生成的值,因此它们对于表示昂贵或不可能一次计算的序列非常有用。这些序列包括无限序列和实时数据流
生成器也应该是非常快的。但请记住,当我们谈论fast时,我们通常谈论的是非常小的数字。因此,在您现在运行并更改所有代码以使用生成器之前,请先做一个基准测试,看看它有何意义
生成器的另一个用例是异步协同路由。yield
关键字不仅返回值,而且还接受值。有关详细信息,请参阅下面链接的两篇优秀博客文章
从什么时候开始我可以使用yield
?
PHP 5.5中引入了生成器。在该版本之前尝试使用yield
将导致各种解析错误,具体取决于关键字后面的代码。因此,如果从该代码中得到解析错误,请更新PHP
资料来源和进一步阅读:
yield
关键字用于PHP5.5中“生成器”的定义。
好的,那么什么是a
从php.net:
生成器提供了一种实现简单迭代器的简单方法,而无需实现实现迭代器接口的类的开销或复杂性
生成器允许您编写使用foreach对一组数据进行迭代的代码,而无需在内存中构建数组,这可能会导致您超出内存限制,或需要相当长的处理时间来生成。相反,您可以编写一个生成器函数,它与普通函数相同,只是为了提供要迭代的值,生成器可以根据需要多次返回
从这里开始:生成器=生成器,其他函数(只是一个简单的函数)=函数
因此,它们在以下情况下非常有用:
- 你需要做一些简单的事情;
生成器实际上比实现迭代器接口简单得多。当然,另一方面,生成器的功能性较差
- 您需要生成大量数据-节省内存;
实际上,为了节省内存,我们可以通过每个循环迭代的函数生成所需的数据,并在迭代后利用垃圾。因此,这里的要点是-清晰的代码和可能的性能。看看什么更适合您的需要
- 您需要生成序列,这取决于中间值;
这是对先前思想的扩展。与函数相比,生成器可以使事情变得更容易。检查并尝试在没有生成器的情况下生成序列。在这种情况下,生成器也可以更快地工作,至少因为在局部变量中存储了中间值
- 您需要提高性能。
在某些情况下,它们可以比功能更快地工作(参见前面的优点)
带有$closure = function ($injected1, $injected2, ...){
$returned = array();
//task1 on $injected1
$returned[] = $returned1;
//I need a breakpoint here!!!!!!!!!!!!!!!!!!!!!!!!!
//task2 on $injected2
$returned[] = $returned2;
//...
return $returned;
};
$returned = $closure($injected1, $injected2, ...);
$closure1 = function ($injected1){
//task1 on $injected1
return $returned1;
};
$closure2 = function ($injected2){
//task2 on $injected2
return $returned1;
};
//...
$returned1 = $closure1($injected1);
//breakpoint between task1 and task2
$returned2 = $closure2($injected2);
//...
$closure = function (){
$injected1 = yield;
//task1 on $injected1
$injected2 = (yield($returned1));
//task2 on $injected2
$injected3 = (yield($returned2));
//...
yield($returnedN);
};
$generator = $closure();
$returned1 = $generator->send($injected1);
//breakpoint between task1 and task2
$returned2 = $generator->send($injected2);
//...
$returnedN = $generator->send($injectedN);
<?php
echo '#start main# ';
function a(){
echo '{start[';
for($i=1; $i<=9; $i++)
yield $i;
echo ']end} ';
}
foreach(a() as $v)
echo $v.',';
echo '#end main#';
?>
#start main# {start[1,2,3,4,5,6,7,8,9,]end} #end main#
<?php
echo '#start main# ';
function a(){
echo '{start[';
for($i=1; $i<=9; $i++)
yield $i;
echo ']end} ';
}
foreach(a() as $k => $v){
if($k === 5)
break;
echo $k.'=>'.$v.',';
}
echo '#end main#';
?>
#start main# {start[0=>1,1=>2,2=>3,3=>4,4=>5,#end main#
function a($items) {
foreach ($items as $item) {
yield $item + 1;
}
}
function b($items) {
$result = [];
foreach ($items as $item) {
$result[] = $item + 1;
}
return $result;
}
<?php
/**
* Yields by reference.
* @param int $from
*/
function &counter($from) {
while ($from > 0) {
yield $from;
}
}
foreach (counter(100) as &$value) {
$value--;
echo $value . '...';
}
// Output: 99...98...97...96...95...
<?php
function sleepiterate($length) {
for ($i=0; $i < $length; $i++) {
sleep(2);
yield $i;
}
}
foreach (sleepiterate(5) as $i) {
echo $i, PHP_EOL;
}
<?php
ini_set('memory_limit','1000M');
echo "Starting memory usage: " . memory_get_usage() . "<br>";
$path = './file.txt';
$content = file_get_contents($path);
foreach(explode("\n", $content) as $ex) {
$ex = trim($ex);
}
echo "Final memory usage: " . memory_get_usage();
Starting memory usage: 415160
Final memory usage: 270948256
<?php
ini_set('memory_limit','1000M');
echo "Starting memory usage: " . memory_get_usage() . "<br>";
function x() {
$path = './file.txt';
$content = file_get_contents($path);
foreach(explode("\n", $content) as $x) {
yield $x;
}
}
foreach(x() as $ex) {
$ex = trim($ex);
}
echo "Final memory usage: " . memory_get_usage();
Starting memory usage: 415152
Final memory usage: 415616