Использование php yield / Generator::send() для "потока вывода данных"

Я знаю, что 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, но, возможно, есть вариант использования для отправки нулевого значения.

Существуют ли "лучшие практики" для использования php-генераторов для последовательной записи?

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

Здесь добавлена ​​небольшая фабрика для дополнительного семантического сахара.

Не идеально, но работает без создания какого-либо другого класса

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());
Другие вопросы по тегам