Что такое оператор throw в PHP?

Ответ

В PHP throw — это оператор, используемый для выброса исключения. Исключение — это объект, сигнализирующий о возникновении ошибки или нестандартной ситуации, которая прерывает нормальный ход выполнения программы. Управление передается ближайшему подходящему блоку catch.

Базовый синтаксис:

throw new Exception('Сообщение об ошибке');

Практический пример с пользовательским исключением:

// 1. Определяем собственный класс исключения для предметной области
class InvalidUserCredentialsException extends Exception {}
class UserNotFoundException extends Exception {}

class AuthService {
    private $userRepository;

    public function login(string $email, string $password): User {
        // 2. Выбрасываем исключение при нарушении бизнес-правила
        $user = $this->userRepository->findByEmail($email);
        if (!$user) {
            throw new UserNotFoundException("Пользователь с email $email не найден.");
        }

        if (!password_verify($password, $user->getPasswordHash())) {
            throw new InvalidUserCredentialsException("Неверный пароль.");
        }

        // Логика успешного входа...
        return $user;
    }
}

// 3. Обрабатываем исключения на более высоком уровне (например, в контроллере)
try {
    $authService = new AuthService();
    $user = $authService->login($_POST['email'], $_POST['password']);
    echo "Добро пожаловать, " . $user->getName();
} catch (UserNotFoundException $e) {
    http_response_code(404);
    echo "Ошибка: " . $e->getMessage();
} catch (InvalidUserCredentialsException $e) {
    http_response_code(401);
    echo "Ошибка: " . $e->getMessage();
} catch (Exception $e) {
    // Общий обработчик для всех непредвиденных исключений
    http_response_code(500);
    error_log($e->getMessage()); // Логируем для разработчика
    echo "Произошла внутренняя ошибка сервера.";
}

Ключевые преимущества использования throw:

  • Разделение ответственности: Код, обнаруживающий ошибку, и код, обрабатывающий ее, разделены.
  • Группировка ошибок: Исключения можно организовывать в иерархии классов.
  • Гарантия обработки: Непойманное исключение приведет к фатальной ошибке, что помогает избежать молчаливого продолжения работы с неверным состоянием.
  • Богатый контекст: Объект исключения может содержать сообщение, код ошибки, стек вызовов и другие данные для отладки.

Ответ 18+ 🔞

Слушай, ну вот реально, объясню тебе про throw в PHP, чтобы ты не наступал на те же грабли, что и я когда-то. Это же ёпта не просто какая-то команда, это, блядь, как аварийный тормоз в коде. Представь: едешь ты на своей тачке, а тут — бац! — яма на дороге. Можно, конечно, проехать и хрустнуть подвеской, а можно выбросить исключение, то есть крикнуть «ёб твою мать!» и остановиться, чтобы разобраться.

Вот смотри, как это выглядит, если по-простому:

throw new Exception('Сообщение об ошибке');

Всё. Кинул и пошёл нахуй. Дальше код не выполняется, управление летит вверх по стеку, пока не найдётся тот, кто это поймает. Если не найдётся — будет тебе фатальная ошибка, и пользователь увидит какую-нибудь дичь. Доверия ебать ноль к такому коду.

Давай на живом примере, чтобы понятно было:

// 1. Создаём свои классы для ошибок. Не надо всё валить в одну кучу.
class InvalidUserCredentialsException extends Exception {}
class UserNotFoundException extends Exception {}

class AuthService {
    private $userRepository;

    public function login(string $email, string $password): User {
        // 2. Ищем юзера. Не нашли? Всё, пиздец.
        $user = $this->userRepository->findByEmail($email);
        if (!$user) {
            throw new UserNotFoundException("Пользователь с email $email не найден, ёпта.");
        }

        // 3. Пароль не сошёлся? Да иди ты нахуй со своим паролем.
        if (!password_verify($password, $user->getPasswordHash())) {
            throw new InvalidUserCredentialsException("Неверный пароль, ядрёна вошь.");
        }

        // Если дошли сюда — всё ок, можно пускать.
        return $user;
    }
}

// 4. А вот тут, на уровне повыше, мы эту всю движуху ловим.
try {
    $authService = new AuthService();
    $user = $authService->login($_POST['email'], $_POST['password']);
    echo "Добро пожаловать, " . $user->getName();
} catch (UserNotFoundException $e) {
    // Пользователя нет — 404.
    http_response_code(404);
    echo "Ошибка: " . $e->getMessage();
} catch (InvalidUserCredentialsException $e) {
    // Пароль кривой — 401.
    http_response_code(401);
    echo "Ошибка: " . $e->getMessage();
} catch (Exception $e) {
    // А это на случай, если вылезет какая-то неведомая хуйня, которую мы не предусмотрели.
    http_response_code(500);
    error_log($e->getMessage()); // Пишем в лог, чтобы потом не охуевать.
    echo "Произошла внутренняя ошибка сервера, бля.";
}

В чём, сука, сила-то?

  • Чистота, мать его. Код, где ошибка возникает, и код, где её обрабатывают, — это два разных места. Один только кричит «всё пропало!», а другой этот крик ловит и решает, что делать. Подозрение ебать чувствую к функциям, которые сами себе и логируют, и пишут в ответ.
  • Иерархия. Можно делать целые семейства исключений, как в примере. UserNotFoundException и InvalidUserCredentialsException — это дети общего Exception. Ловить можно как конкретного ребёнка, так и папу.
  • Жёсткий контроль. Если исключение не поймать — скрипт умрёт. Это, в общем-то, хорошо, потому что лучше умереть красиво, чем работать в ебучем неконсистентном состоянии. Терпения ноль ебать у программы в таком случае.
  • Вся информация при тебе. В объекте исключения лежит и сообщение, и код строки, и стек вызовов — овердохуища данных для дебага. Не надо ничего руками в логи пихать.

Короче, throw — это не про «ой, что-то пошло не так, ну и ладно». Это про то, чтобы чётко и громко заявить о проблеме и заставить тот код, который вызвал твой, эту проблему решить. Иначе — будет вам хиросима и нигерсраки в продакшене. Используй с умом.