Использование 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());