Как отловить исключение, генерируемое генератором, и возобновить итерацию? - PullRequest
0 голосов
/ 13 июня 2018

У меня есть генератор, который передает коллекцию значений в метод и выдает результат.Вызываемый метод может вернуть исключение.Когда это происходит, я бы хотел, чтобы исключение провалилось в код, который вызывает генератор для обработки исключения, а затем продолжил цикл генератора.

Чтобы проиллюстрировать это, ниже приведен пример генератора, который будетyield 1, бросить \Exception, затем yield 3.

/** @var \Generator $gen */
$gen = function () {
    for ($i = 1; $i <= 3; $i++) {
        if ($i == 2) {
            throw new \Exception('Exception thrown for 2');
        }

        yield $i;
    }
};

Это пример моей попытки запустить этот код, напримерчто я могу получить его, чтобы получить 3

$g = $gen();

var_export($g->current());
echo "\n";

try {
    $g->next();
    var_export($g->current());
    echo "\n";
} catch (\Exception $e) {
    echo $e->getMessage() . "\n";
}

try {
    $g->next();
    var_export($g->current());
    echo "\n";
} catch (\Exception $e) {
    echo $e->getMessage() . "\n";
}

Ниже приведен вывод вышеприведенного кода.

1
Exception thrown for 2.
NULL

Итак, повторные вызовы next() ничего не делает и current() вернет NULL, где я бы хотел, чтобы генератор продолжил работу после исключения, чтобы я мог получить 3.

1 Ответ

0 голосов
/ 13 июня 2018

Создание исключения внутри генератора полностью его закрывает, поэтому на третьей итерации оно возвращает «NULL».Если вы попробуете $g->valid() после выброса исключения, вы получите false в результате.

Вы должны обработать исключения внутри генератора, вы даже можете выбросить их внутри генератора, используя $g->throw() метод.Для получения дополнительной информации проверьте документацию

Однако , то, что вы пытаетесь достичь, возможно.Вы можете yield исключение вместо броска.Таким образом, вы не закроете генератор и сможете обработать исключение снаружи.

Попробуйте этот код:

$gen = function () {
    for ($i = 1; $i <= 3; $i++) {
        // If something wrong happens
        if ($i == 2) {
            // Instead throwing the exception yield it
            // that way we don't close the generator
            yield new \Exception('Exception thrown for 2');
        } else {
            yield $i;
        }
    }
};

И протестируете его с помощью:

$g = $gen();
for ($i = 0; $i < 3; $i++) {
  $current = $g->current();

  // Instead of catching, check if the yielded value is Exception
  if ($current instanceof \Exception) {
      // Handle the exception directly
      // or throw it with throw $current to handle it in normal try-catch block
      echo $current->getMessage() . "\n";
  } else {
      echo $current . "\n";
  }

  $g->next();
}

ДаетВы результат:

1
Exception thrown for 2
3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...