Рекомендации: использование @throws в php-doc и как его можно обрабатывать

предположим, у меня есть класс с таким методом:

/*
 *
 * Loads the user from username.
 *
 * @param string $username The username
 *
 * @return UserInterface
 *
 * @throws userNotFoundException if the user is not found
 */
public function getUser($username)
{
    // someFunction return an UserInterface class if found, or null if not.
    $user = someFunction('SELECT ....', $username);
    if ($user === null) {
        throw new userNotFoundException();
    }

    return $user
}

теперь скажем, что someFunction могу кинуть InvalidArgumentException / RuntimeException / PDOException по причинам XYZ. Что мне делать? а что нет?

номер 1

добавить все возможные исключения, которые может бросать someFunction в php-документах.

/*
 *
 * Loads the user from username.
 *
 * @param string $username The username
 *
 * @return UserInterface
 *
 * @throws userNotFoundException if the user is not found
 * @throws InvalidArgumentException
 * @throws ...
 */

номер 2

добавьте блок try-catch, чтобы гарантировать, что метод должен выдавать только исключения документально

/*
 *
 * Loads the user from username.
 *
 * @param string $username The username
 *
 * @return UserInterface
 *
 * @throws userNotFoundException if the user is not found
 * @throws RuntimeException 
 */
public function getUser($username)
{
    try {
        $user = someFunction('SELECT ....', $username);
    } catch (Exception $e) {
        throw new RuntimeException();
    }

    if ($user === null) {
        throw new userNotFoundException();
    }

    return $user
}

число 3

ничего не делай.

3 ответов


лично я бы рассматривать @throws подобно проверенным исключениям Java

способ, которым это работает в Java, заключается в том, что в основном исключения, наследуемые от RuntimeException, могут быть брошены и не должны обрабатываться. Любые другие типы исключений должны иметь блок try-catch для их обработки. Этот код обработки должен быть в вызывающем объекте.

в основном, в PHP вроде этого:

когда метод имеет @throws аннотация обязательно добавьте код для обработки исключений.

любые исключения, которые не упоминаются, являются необязательными для обработки в вызывающем коде.


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


что касается документации, если функция явно создает исключение, затем оно должно быть включено в документацию функции. Таким образом, для каждого throw оператор, должен быть соответствующий @throws в документации PHP.

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

обновление:

несколько лет спустя я изменил мнение, что нужно только позволить исключению "пузыриться" немодифицированным, когда исключение все еще имеет отношение к уровню абстракции модуля. Стратегии перехвата и повторного броска должны использоваться, чтобы сделать исключение более значимым. Он также должен сделать обработку ошибок более безопасной, избегая ненужного раскрытия информации о модулях, лежащих в основе абстракции.

/**
 * @throws UserNotFoundException
 */
public function getUser($username)
{
    try {
        $user = someFunction('SELECT ....', $username);
    } catch (DatabaseException $dbe) {

        /* Re-throw since a database exception may no longer be
         * meaningful to the caller.
         */
        throw new UserNotFoundException();
    }

    return $user
}

с точки зрения обслуживания документации я бы только добавил строки @throw для исключений, которые специально брошены, иначе вы быстро получите свою документацию устаревшей.