Когда вы должны использовать исключения PHP? - PullRequest
13 голосов
/ 15 декабря 2010

Я видел много учебных пособий, которые демонстрируют простую попытку, скажем, с помощью процесса открытия файла.Но я никогда не видел большого, «реального» примера.Может ли кто-нибудь предоставить мне несколько случаев, в которых они имеют или будут использовать исключения?И действительно ли необходимо расширять класс исключений только для того, чтобы вызвать исключение?И, наконец, при возникновении исключений вызывает ли скрипт выход ();?Или это регистрирует это и продолжает выполнение сценария?

Ответы [ 7 ]

5 голосов
/ 15 декабря 2010

Мы широко используем исключения в наших проектах.

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

Используя наше регистрационное действие в качестве примера, мы расширяем Исключение следующим образом:

class RegistrationFailed extends Exception {}

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

try {
    // do registration here
}
catch(RegistrationFailed $e) {
    // handle the failed registration
}
catch(SomeOtherException $e) {
    // handle other errors like this...
}

// All other errors will not be caught and will bubble up

Другой пример - в наших классах-оболочках, которые разработчики должны расширять. Мы используем Reflection, чтобы гарантировать, что дочерние классы правильно реализовали свои методы и предоставили правильный интерфейс. Если нет, мы уведомляем разработчика этого класса через исключения, сообщая им о том, что конкретный интерфейс или метод должен быть предоставлен дочерним классом.


Edit: Я уже слышу комментарии о "Вы не должны использовать обработку ошибок для контроля потока!" однако для проекта, о котором говорилось выше, это было необходимо.

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

Однако это ajax-приложение, поэтому возможно, что кто-то попытается получить доступ к URL-адресу ajax вручную, когда он не вошел в систему. Это является как исключение, и поэтому мы обрабатываем его как таковой.

5 голосов
/ 15 декабря 2010

Исключения предназначены для обработки ошибок (по крайней мере, в PHP).Предположим, что вы выполняете процедуру, и произошла ошибка, которую вы не можете обработать в текущем контексте.

Пример:

<?php
/**
 * @throws Exception_NoFile
 */
function read_file($file) {
    if(!file_exists($file)) {
        throw new Exception_NoFile($file);
    }

    /* ... nominal case */
}

В этой ситуации вы не можете продолжить сноминальный случай, потому что нет файла для обработки.Вы должны выбрать:

  • возврат с недопустимым возвращаемым значением (это практика C, например, возврат -1 или использование флагов состояния)

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

3 голосов
/ 15 декабря 2010

Вы должны проверить платформу Symfony - там действительно используется множество исключений.

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

Они используют Исключение для неизвестных ошибок: база данных завершилась неудачей по какой-то странной причине, фреймворк ничего не может с этим поделать - поэтому он выдает Исключение1005 *

И у них разные обработчики исключений для разных сред.Когда происходит исключение в режиме «devel», вы получаете хорошую страницу с трассировкой стека и объяснением, а когда вы находитесь в «производственном» режиме, вы перенаправляетесь на пользовательскую страницу 500.

2 голосов
/ 30 декабря 2016

Обработка исключений сложна.Это требует тщательного рассмотрения проекта и способов устранения ошибок.Вы должны попытаться определить Руководство по исключениям в начале вашего проекта и придерживаться его.

Я написал общие Руководства по исключениям лучшие практики, которые я придумал после обширных исследований предмета.Большинство из этих рекомендаций могут быть использованы для всех проектов на любом языке, который поддерживает исключения.Некоторые из рекомендаций будут специфичными для Java.В конце вы должны иметь надежный набор рекомендаций, которые могут помочь вам справиться с исключениями и ошибочными ситуациями и справиться с ними.

Вот несколько моментов, которые следует учитывать

Не раскрывайте внутреннюю реализациюспецифические детали для ваших клиентов

Избегайте предоставления вашим клиентам особых исключений, связанных с внутренней реализацией, особенно тех, которые содержатся в сторонней библиотеке.Это общее объектно-ориентированное эмпирическое правило, которое применимо и к вашей структуре иерархии исключений.Вы не можете контролировать стороннюю библиотеку, которая может изменять сигнатуры исключений и нарушать все ваши контракты API с вашими клиентами.Вместо этого включите эти сторонние исключения (например, SQLException) в ваши собственные пользовательские исключения.Таким образом, у вас будет гораздо больше возможностей для изменения сторонней библиотеки в будущем без нарушения контракта API ваших клиентов.

Создание собственной иерархии исключений для сложных проектов

Вообще говоря, создайте своюсобственная иерархия исключений для более сложных модулей, особенно если вы имеете дело со специфическими для реализации исключениями в сторонних библиотеках.Каждый из ваших пакетов / модулей может иметь свои собственные общие исключения верхнего уровня.Для Java должен быть определен, по крайней мере, один, который наследуется от RuntimeException.Оберните все специфичные для реализации исключения в ваши пользовательские исключения, чтобы ваши клиенты зависели только от ваших пользовательских исключений и / или общих исключений Java.Это даст вам большую гибкость для последующего рефакторинга кода, специфичного для реализации, без нарушения ваших контрактов API.

Если требуется более детальная обработка ошибок, вы можете дополнительно подклассифицировать свои пользовательские исключения для обработки конкретных случаев и обеспечения восстановления после ошибок.,Например, если вы подключаетесь к базе данных SQL, вы можете вызвать исключение ConnectionTimeoutException таким образом, чтобы при необходимости клиент мог повторить соединение N раз, прежде чем отказаться.Таким образом, впоследствии вы можете изменить ядро ​​базы данных на NoSQL и по-прежнему разрешать повторное подключение, а код клиента останется прежним.

Документирование всех исключений

Тщательно документируйте все исключения вашего пакета / модуля / приложениядобавляет определение javadoc для каждого открытого метода.Невыполнение этого требования приведет к разочарованию пользователей API и приведет к тому, что они не будут доверять вашим документам API.Вы на самом деле не хотите, чтобы ваши клиенты копались в вашем источнике, просто чтобы узнать, что вы генерируете конкретное исключение, верно?

Бросайте исключения как можно раньше.

Проверьте все входные данные дляваши публичные методы API и выведите исключение, как только вы обнаружите несоответствия между вашими ожидаемыми параметрами и тем, что было предоставлено.Чем раньше вы создадите исключение, тем меньше вероятность повреждения данных, потому что плохие данные не попадут в более глубокие части вашего кода.Это также дает ценные отзывы вашим клиентам своевременно, а не глубоко в вашем коде, где что-то вызывает неясное исключение с плохим сообщением, таким как «Внутренняя ошибка» или NullPointerException.

Правильно регистрируйте исключения

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

2 голосов
/ 30 декабря 2016

Я чувствую, что многие люди путают «неудачи» и «исключения» как одно и то же. Слово «ошибка» может относиться к любому из них, но я использую его для неудачи.

Сбой - когда операция не удалась

Исключение - при возникновении неожиданного или нестандартного состояния потока

Например, если робот пытается пройти к месту назначения и пропускает отметку - это неудача. Но если он сломает ногу или упадет крыша, это исключение.

Если крыша падает, я исключаю, что крыша упала.

Если робот пропускает отметку, я не выкидываю исключение, я возвращаю false или возвращаю сообщение об ошибке типа «Не удалось добраться до пункта назначения из-за падения крыши».

try {
  Walk to the cabinet;
}
catch (RoofFell_Exception $e) {
  return "Could not reach the destination because the roof fell.";
}
catch (Legbroke_Exception $e) {
  return "Could not reach the destination because a leg broke.";
}

if($current_location == 'cabinet') {
  return "Destination reached";
}
return false;
0 голосов
/ 01 февраля 2015

Отличное место для использования обработки исключений - это когда ваша программа пытается подключиться или получить доступ к вводу / выводу (файлы, базы данных, сети, устройства).

  1. Использовать обработку исключенийкогда блок вызывающего кода (функция / метод) пытается получить доступ к файлу .

  2. Использовать обработку исключений при попытке блока вызывающего кода (функция / метод) соединение с базой данных .

  3. Использовать обработку исключений, когда блок вызывающего кода (функция / метод) пытается выполнить запрос в базе данных(любая попытка доступа к таблицам / представлениям базы данных и т. д.).

  4. То же самое можно сказать о сетевом подключении или доступе .

Для доступа к памяти требуется ввод-вывод (который включает в себя хранение вещей в файлах $ _SESSION), но большинство начинающих не помещают всю свою программу в пределы структуры try...catch.Хороший пример использования исключений и расширения класса Exception можно найти в книге Мэтта Дойла Beginning PHP 5.3 , ch.20, с.652-60.

Я мог бы также сказать, что научившись сочетать использование обработки исключений с set_error_handler(), trigger_error(), error_log() внутри блока catch, вы сможете сохранить пользовательский, разработчикдружественные сообщения об ошибках, которые вы, возможно, выводили на ваше устройство вывода (браузер / стандартный вывод) в процессе разработки.То есть в работе ваш php.ini отключит display_errors, а log_errors будет включен.Если вы могли повторить что-то вроде «К сожалению, я не могу подключиться к базе данных учета», когда не удалось подключиться к указанной базе данных, просто отправьте эту же строку текста на error_log(), и ваши личные сообщения об ошибках все еще могут быть зарегистрированы.

Пример:

function custom_handler($arg1, $arg2, $arg3, $arg4, $arg5)
{
  ...
  ...
  error_log(blah, blah, blah)
}

set_error_handler('custom_handler');  <--takes over this duty from PHP
$error = NULL;

try
{
     if(!connect_to_mythical_database('accounting'))
     {
          $error = 'I cannot connect to the accounting database';
          throw new Exception(supply-correct-arguments);
     }
}
catch (Exception $e)
{
     trigger_error(supply-correct-arguments); <-- does what 'custom_handler' instructs.
     error_log($error, blah, blah); <---Your friendly message here
     header('Location: http://www.myhomepage.com');
     exit;
}

Примечание : Внутри custom_handler() вы можете использовать error_log(), чтобы регистрировать сообщения об ошибках PHP в файле, отправлять их по электронной почте или регистрировать ипо электронной почте стандартные сообщения об ошибках PHP.Таким образом, trigger_error() управляется либо PHP (по умолчанию), либо вашим 'custom_handler', который может реализовать error_log()', all of which can be activated by the catch` блок вашего обработчика исключений.

0 голосов
/ 15 декабря 2010

Исключения - это просто способ переместить крайние случаи или ошибки (которые на самом деле являются просто большими крайними случаями) из большей части кода, чтобы не дать им загромождать 99% основного потока кода тоннами переключателей./ifs.

Вы можете рассматривать их как своего рода оператор обратного переключения, где события внутри try {} определяют, какой, если таковой имеется, блок catch тоже происходит.

Что это значитв том, что вам никогда не придется их использовать, если они вам не нравятся.Но они могут облегчить чтение кода.

...