Повторное выбрасывание частично пойманные исключения?

Обновить

December 2018

Просмотры

224 раз

4

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

do {
        ...
   } catch (PDOException $e) {
       if ($e->getCode() === '23000') {
          continue; // have another go
      } else {
          throw new Exception("...", 1, $e); // reraise
      }
} while(there was an exception);

Я думаю, что перехват ошибок будет лучше, чем поиск-то вставить, потому что с четырехзначным кодом, и только несколько сотен активных кодов в любой момент времени будет мало столкновений.

С.О. вопросы , как лучшие практики для ловли и вновь бросать исключение? и исключение Rethrow PHP в более высокий уровень улова блока показывают , что даже в PHP это плохая практика. Я как поймать исключение , я 99% уверен , что я собираюсь повторно выдать, и я использую исключение для управления потоком.

Есть ли лучший способ сделать это в PHP, или моя единственная альтернатива использовать хранимую процедуру в базе данных, которая возвращает код ошибки при неудаче, а не исключением.

2 ответы

3

Мой вывод заключается в том, что там на самом деле нет лучшего способа сделать это в PHP, так что я переехал логику в MySQL, где она несколько меньше некрасиво. Я использую обработку ошибок, а не искать, потому что будет быстрее обычного случая, когда нет никакого столкновения.

Выполнение поиска первым будет медленнее, гораздо медленнее, в PHP (два или более запросов) и немного медленнее для нормального случая в SQL (один дополнительный запрос), но если есть много коллизий будет быстрее, чтобы сделать поиск первый а не провал на вкладыше.

DECLARE CONTINUE HANDLER FOR 1062 -- duplicate key
    SET @dupe = 1;

SET @dupe = 0;
SET @attemptsLeft = 5;
REPEAT
    SET @user_code = randomString(4);
    INSERT INTO mytable(expires, user_code, users_id)VALUES(p_expires, @user_code, p_users_id);
    SET @attemptsLeft = @attemptsLeft - 1;
    -- if there's a dupe we get the continue handler above
UNTIL @dupe = 0 OR @attemptsLeft <= 0 END REPEAT;
2

Если вы хотите повторно бросить то же самое исключение, почему бы вам не использовать просто:

throw $e;

Связанные вопросы