【问题标题】:Using php yield / Generator::send() for a "data output stream"将 php yield / Generator::send() 用于“数据输出流”
【发布时间】:2017-03-15 22:55:39
【问题描述】:

我知道 yield 可用于创建数据迭代器,例如从 CSV 文件中读取数据。

function csv_generator($file) {    
  $handle = fopen($file,"r");
  while (!feof($handle)) {
    yield fgetcsv($file);
  }
  fclose($file);
}

但是 Generator::send() 方法表明我可以对顺序写入执行相同的操作,而不是读取。

例如我想用这样的东西:

function csv_output_generator($file) {
  $handle = fopen('file.csv', 'w');
  while (null !== $row = yield) {
    fputcsv($handle, $row);
  }
  fclose($handle);
}

$output_generator = csv_output_generator($file);
$output_generator->send($rows[0]);
$output_generator->send($rows[1]);
$output_generator->send($rows[2]);
// Close the output generator.
$output_generator->send(null);

我认为以上方法可行。

但是$output_generator->send(null); 关闭似乎是错误的,或者不理想。这意味着我永远不能发送文字空值。这对于 csv 编写来说是可以的,但也许有一个发送 null 的用例。

有没有使用php生成器进行顺序编写的“最佳实践”?

【问题讨论】:

  • 这不仅仅是生成器的问题。您确实有 while (!feof($handle)) ,您需要在到达文件末尾后检查 1 次。这是同样的问题。
  • 好吧,我们在这里讨论语义。您也可以发送truefalsenull 等。这是您的电话。你用null tho 提出了一个公平的观点。我不知道,我想我会发送一些冗长的字符串之类的东西,但这也是我不设计系统的原因,这可能是一个可怕的想法。
  • @apokryfos 但由于 feof() 是一个单独的函数,它不会限制 fgetcsv() 可能返回值的范围。当然这对 csv 毫无意义,因为如果 fgetcsv() 返回 null,我们就知道它是 EOF。输入迭代器已经为 ->valid() 和 ->current() 设计了单独的方法,因此 ->current() 可以返回 null 而不意味着 EOF。但不适用于输出/写作。
  • @Andrew 我选择了 null 因为如果没有发送任何内容,yield 已经碰巧返回 null。是的,我可以为此选择不同的魔法值。但理想情况下,我不会使用 send() 方法来关闭流,而是使用专用的 ->close() 方法。 (不存在)。
  • 顺便说一句 ->close() 方法有时对阅读也很有用。例如。在 EOF 之前关闭 csv 文件句柄。

标签: php php-generators


【解决方案1】:

并不是说这是一个了不起的想法,但如果你在谈论语义,这“感觉”很棒。

检查一个类。就像传入特定类的对象以终止生成器一样。喜欢:

// should probably use namespacing here.
class GeneratorUtilClose {}

class GeneratorUtil {
    public static function close() {
        return new GeneratorUtilClose;
    }
}

function csv_output_generator($file) {
  $handle = fopen('file.csv', 'w');

  while (!(($row = yield) instanceof GeneratorUtilClose)) {
    fputcsv($handle, $row);
  }

  fclose($handle);
}

$output_generator = csv_output_generator($file);
$output_generator->send($rows[0]);
$output_generator->send(GeneratorUtil::close());

在这里添加了一个小工厂以获得额外的语义糖。

【讨论】:

  • 是的,这将起作用,并且允许发送文字 NULL。我不确定这是否真的是整体上的改进,但我会说这是一个有效的答案。
【解决方案2】:

也不理想,但无需创建任何其他类即可工作

function csv_output_generator($file) {
  $handle = fopen($file, 'w');
  try {
    while ($row = yield) {
      fputcsv($handle, $row);
    }
  } catch (ClosedGeneratorException $e) {
    // closing generator
  }

  fclose($handle);
}

$output_generator = csv_output_generator($file);
$output_generator->send($rows[0]);
$output_generator->send($rows[1]);
$output_generator->send($rows[2]);
// Close the output generator.
$output_generator->throw(new ClosedGeneratorException());

【讨论】:

    猜你喜欢
    • 2015-02-21
    • 2013-11-15
    • 1970-01-01
    • 2016-09-08
    • 2015-08-17
    • 2016-10-15
    • 2011-06-06
    • 1970-01-01
    • 2021-06-12
    相关资源
    最近更新 更多