W3docs

try

Узнайте, как PHP try/catch/finally обрабатывает исключения. Несколько блоков catch, union-типы, повторный выброс и типичные ошибки.

Ключевое слово PHP try

Ключевое слово try помечает блок кода, который может выбросить исключение — объект, сигнализирующий о том, что что-то пошло не так и нормальное выполнение невозможно. Когда внутри блока try выбрасывается исключение, PHP прекращает выполнение оставшейся части этого блока и ищет подходящий блок catch для его обработки. Необязательный блок finally выполняется в любом случае, независимо от произошедшего.

На этой странице рассматриваются синтаксис try/catch/finally, правила сопоставления нескольких блоков catch, перехват нескольких типов исключений одновременно, повторный выброс и типичные подводные камни. Если вы только знакомитесь с понятием выброса ошибок, сначала прочитайте Исключения в PHP.

Синтаксис

try {
  // Code that may throw an exception
} catch (ExceptionType $e) {
  // Code that runs if an exception of ExceptionType (or a subclass) is thrown
} finally {
  // Optional: always runs, whether or not an exception was thrown
}

За блоком try должен следовать хотя бы один блок catch, или блок finally, или обаtry без них является синтаксической ошибкой. Переменная в catch (ExceptionType $e) содержит объект выброшенного исключения, который можно опросить методами, например $e->getMessage().

Первый пример

Функция ниже выбрасывает исключение при попытке делить на ноль. Блок try вызывает её, блок catch сообщает о проблеме, а finally выполняется всегда:

<?php

function divide($dividend, $divisor)
{
  if ($divisor == 0) {
    throw new Exception("Cannot divide by zero.");
  }
  return $dividend / $divisor;
}

try {
  $result = divide(10, 0);
  echo $result;            // skipped — divide() threw before returning
} catch (Exception $e) {
  echo "Error: " . $e->getMessage() . PHP_EOL;
} finally {
  echo "Done." . PHP_EOL;
}

Вывод:

Error: Cannot divide by zero.
Done.

Обратите внимание, что echo $result; никогда не выполняется: как только divide(10, 0) выбрасывает исключение, управление немедленно переходит к блоку catch. Блок finally выполняется после него. Если вызвать divide(10, 2), исключение не выбрасывается, блок try выводит 5, и finally всё равно выводит Done..

Несколько блоков catch

За одним блоком try может следовать несколько блоков catch. PHP проверяет их сверху вниз и выполняет первый, тип которого совпадает с выброшенным исключением (совпадение учитывает подклассы). Размещайте более специфичные типы перед более общими — ведущий catch (Exception $e) перехватит всё, что идёт ниже.

<?php

try {
  $value = "5";
  if (!is_int($value)) {
    throw new TypeError("Expected an integer.");
  }
} catch (TypeError $e) {
  echo "Type problem: " . $e->getMessage() . PHP_EOL;
} catch (Exception $e) {
  echo "Other problem: " . $e->getMessage() . PHP_EOL;
}

Вывод:

Type problem: Expected an integer.

Перехват нескольких типов в одном блоке

Когда два типа исключений должны обрабатываться одинаково, объедините их вертикальной чертой (|) — функция, добавленная в PHP 7.1, — вместо дублирования блока:

<?php

try {
  throw new RuntimeException("Network timed out.");
} catch (RuntimeException | LogicException $e) {
  echo "Handled: " . $e->getMessage() . PHP_EOL;
}

Вывод:

Handled: Network timed out.

Поведение finally

Блок finally выполняется даже если в блоке try или catch есть оператор return. Это делает его идеальным местом для очистки ресурсов — закрытия файлов, снятия блокировок, отката транзакций — которая должна происходить при любом сценарии:

<?php

function readConfig()
{
  try {
    return "config loaded";
  } finally {
    echo "Cleanup ran." . PHP_EOL;
  }
}

echo readConfig() . PHP_EOL;

Вывод:

Cleanup ran.
config loaded

Блок finally выполняется до того, как функция фактически возвращает своё значение. Избегайте возврата из самого finally: оператор return там переопределяет значение из try/catch и молча игнорирует любое выброшенное исключение.

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

Блок catch может выполнить частичную работу — записать ошибку в журнал, добавить контекст — и затем повторно выбросить исключение, чтобы вызывающий код выше мог решить, что с ним делать. Используйте throw $e; для повторного выброса того же объекта:

<?php

try {
  try {
    throw new Exception("Disk full.");
  } catch (Exception $e) {
    echo "Logging: " . $e->getMessage() . PHP_EOL;
    throw $e; // hand it to the outer handler
  }
} catch (Exception $e) {
  echo "Outer handler: " . $e->getMessage() . PHP_EOL;
}

Вывод:

Logging: Disk full.
Outer handler: Disk full.

Типичные подводные камни

  • try нужен партнёр. Блок try сам по себе не разберётся — дополните его хотя бы одним catch или блоком finally.
  • Не все ошибки — исключения. Многие runtime-предупреждения (неопределённая переменная, неудачный fopen()) не выбрасываются как исключения, поэтому catch их не увидит. Используйте set_error_handler() или проверяйте возвращаемые значения. Фатальные объекты Error (например, TypeError) можно перехватить, поскольку они реализуют Throwable.
  • Располагайте блоки catch от частного к общему. Широкий catch (Exception $e), стоящий первым, скрывает все последующие блоки.
  • Неглотайте ошибки молча. Пустой блок catch скрывает сбой; как минимум записывайте $e->getMessage() в журнал, чтобы проблема была видна.
  • finally может маскировать исключения. Возврат из finally отбрасывает и значение, возвращаемое блоком try, и любое летящее исключение.

Когда использовать try?

Прибегайте к try/catch, когда сбой является исключительным и вызывающий код может разумно на него отреагировать: потеря соединения с базой данных, ошибка в ответе API, некорректные данные пользователя, которые нужно отклонить. Для обычного управления потоком (был ли ключ найден в массиве? пуста ли строка?) используйте обычные условные операторы — исключения предназначены для нештатных ситуаций, а не для повседневного ветвления.

Связанные темы

  • catch — блок, обрабатывающий выброшенное исключение.
  • finally — код, который всегда выполняется после try/catch.
  • throw — самостоятельный выброс исключения.
  • Класс Exception — базовый тип и его методы.
  • Исключения в PHP — общая картина обработки ошибок.
  • set_exception_handler() — перехват исключений, вышедших за пределы каждого блока try.

Практика

Практика
Какой тег используется в PHP для начала блока кода?
Какой тег используется в PHP для начала блока кода?
Was this page helpful?