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

don*_*ote 5 php php-generators

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

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

但是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);
Run Code Online (Sandbox Code Playgroud)

我认为以上方法会起作用。

但是$output_generator->send(null);对于关闭似乎是错误的,还是不理想的。这意味着我永远无法发送原义的null。可以用csv编写,但是也许有一个发送null的用例。

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

Omr*_*mal 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());
Run Code Online (Sandbox Code Playgroud)

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