Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在PHP中,收益率意味着什么?_Php_Generator_Php 5.5_Yield Keyword - Fatal编程技术网

在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