封闭产量

时间:2018-03-07 11:50:45

标签: php php-7.2

我想提供一些数据。问题是chunk方法需要关闭才能完成工作。在这种情况下,是否可以通过foreach循环生成数据?

public function yieldRowData(): \Iterator
{
    $this->transactionQuery
        ->getQuery()
        ->chunk(5, function ($collection) { // This is executed for each 5 elements from database
            foreach ($collection as $element) {
                yield $element->getId(); // I want this to be yield from this method (yieldRowData)
            }
        });
}

我尝试了这个,但它只返回最后的结果:

public function yieldRowData(): \Iterator
{
    $results = [];

    $this->transactionQuery
        ->getQuery()
        ->chunk(5, function(Collection $transactions) use (&$results) {
            $results = $transactions;
        });

    foreach($results as $transactionEntity) {
        yield $transactionEntity;
    }
}

2 个答案:

答案 0 :(得分:0)

您没有明确提及chunk()方法(或其他方法)是否从闭包内部返回生成的数据;但我想不会。

如果返回(即它是一个生成器函数),则yield from是最佳选择:

// We are inside the method
yield from $query->chunk(5, function ($collection) {
    foreach ($collection as $element) {
        yield $element->getId();
    }
});

但是,如果它不是生成器函数,则必须使用其他解决方案。就像其他人提到的那样,您可能不想将结果保存在变量中并返回它,因为它浪费了内存(尤其是在大数据量上)。

但是还有另一种可行的解决方案。如果幸运的话,chunk()中的代码将不会很复杂,因此您可以从其类扩展并重写chunk()方法作为生成器。您可能无法做到这一点,但通常是可以做到的,而且并不困难或费时。

答案 1 :(得分:-1)

尝试这一点,它应该更像你的第一次尝试,同时实际上产生一些明智的东西:

public function yieldRowData(): \Iterator
{
    $results = [];

    $this->transactionQuery
        ->getQuery()
        ->chunk(5, function(Collection $collection) use (&$results) {
            foreach ($collection as $element) {
                $results[] = $element->getId();
            }
        });

    foreach($results as $transactionEntity) {
        yield $transactionEntity;
    }
}

为以下评论添加其他想法: 将闭包传递给yieldRowData()以便使用chunk的内存效率:

public function workRowData(\closure $rowDataWorker)
{
    $this->transactionQuery
        ->getQuery()
        ->chunk(5, $rowDataWorker);
}

$rowDataWorker可以绑定到应该包含某些最终结果的变量,或者可以使用$this来访问实例变量。