使用php yield / Generator::send()获取“数据输出流”


Using php yield / Generator::send() for a "data output stream"

我知道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);似乎是错误的,或者是不理想的。这意味着我永远不能发送一个文字null。这是ok的csv写入,但也许有一个用例发送null。

是否有使用php生成器进行顺序写入的"最佳实践"?

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

检查一个类。比如传入特定类的对象来终止生成器。如:

// 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());

为额外的语义糖添加了一个小工厂

也不理想,但不需要创建任何其他类

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());