Как правильно использовать исключения

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

    Изучив синтаксис конструкции try{...}catch(Exception $e){...}, узнав о возможности создавать собственные классы исключений, наследуя их от класса Exception и поверхностно осознав мощь оказавшегося в ваших руках механизма, дальше вы можете пойти по одному из двух путей:
    • Начать тут же использовать исключения. Скажем, прикручивать их к системе, в которой они никогда не использовались. Или приколачивать их к проекту, в котором ООП и не пахнет. Или, что самое ужасное, пытаться использовать их повсеместно, особенно там, где это не нужно.
    • Попытаться понять, где их применять, как делать это правильно, и зачем они нужны.


    1. Нужно уметь чётко отличать в программе исключительную ситуацию от рядовой ошибки, например: неправильно введённые логин или пароль — это не исключительная ситуация! Это ошибка пользователя, а не программы, и она может происходить оченьчасто. С другой стороны, сбой в работе функции mysql_connect() из-за недоступности сервера БД — это исключительная ситуация, исключение нужно бросать! Подробнее об этом дальше.

    2. Методы класса не должны перехватывать исключения, сгенерированные другими методами этого же класса. Библиотека вообще ничего не должна знать о том, что делать в случае возникновения исключительной ситуации в её методах, так как в зависимости от системы, где она используется, это поведение может сильно различаться. Её дело — сгенерировать исключение. К примеру, если файла, требующегося для корректной работы всего вашего класса, не существует, вы не должны с этим разбираться. Это дело вышестоящих уровней приложения.

    С другой стороны, перехватывать исключения, брошенные нижестоящими уровнями, Вы вполне можете (если хотите). Если не хотите, они будут переданы по стеку в ближайший catch{} (точнее в catch{}, соответствующий ближайшему try{} ). Допустим, у вас есть класс-обёртка для работы с БД, с методами типа connect(), query() и так далее. Разумеется, если к серверу подключиться не удаётся, необходимо сгенерировать исключение в методе connect().

    Однако перехватывать его не должен ни сам метод connect(), ни даже метод query(), который мог вызвать connect() автоматически! Данное исключение должно быть перехвачено на вышестоящем уровне, который работает с методами этого класса, и там должно быть принято решение — попробовать подключиться к другому серверу, использовать другой тип источника данных, просто вывести на экран ошибку, или передать исключение ещё выше (в разных системах по-разному, пускай сами решают, что делать). Надеюсь, мысль понятна.

    3. В крупном приложении необходимо использовать свои собственные классы исключений (унаследованные от встроенного Exception). Это позволяет выстроить иерархию классов ошибок и разделять их по важности, типу и так далее. Допустим, у нас есть класс Application_Exception:

    class Application_Exception extends Exception{...}
    и несколько его потомков:


    class Logic_Exception extends Application_Exception{...}
    -- логические ошибки, например, нарушение связности таблиц в БД или уникальности ключей.


    class Data_Access_Exception extends Application_Exception{...}
    -- ошибки доступа к необходимым данным, вроде отсутствия файла, или устройства, или связи для доступа к какому-то источнику.


    class Security_Exception extends Application_Exception{...}
    -- ошибки с безопасностью, например человек присылает куку, которой у него просто не может быть ;)


    Все эти типы ошибок должны обрабатываться по-разному, например, про ошибки с безопасностью не стоит кричать на весь интернет, а вот в случае отказа сервера БД можно вывести интеллигентную табличку с извинениями (в общем, на вкус и цвет).

    4. Для получения максимального количества информации об ошибке, используйте возможности встроенного класса Exception, не изобретайте велосипедов! Если вам недостаточно имени файла и строки, где было брошено исключение, к вашим услугам методы getTrace() и getPrevious(), которые уж точно выложат перед вами всю «картину» произошедшего (подробнее в документации).

    В этой заметке я попытался изложить основные теоретические положения, которые считаю наиболее важными при использовании исключений. Оригинал записи находится в моём блоге.
    Желаю удачи!
    Share post

    Comments 98

      +1
      Спасибо.
        0
        На здоровье!
        +1
        Отличная статья, спасибо. И блог у Вас интересный :)
        +10
        1. Формальный подход требует, чтобы в случае невозможности аутентификации выбрасывалось AutentificationException. С точки зрения общности и целостности восприятия кода это тоже наиболее эффективно — не надо думать, ошибка ли это, или не ошибка. Исключительная ситуация — это любая ситуация, когда поведение программы отличается от нормального. В том числе, и ввод неверного логина и пароля.

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

        2. Каждая функция, которую вы пишете, должна знать обо всех исключениях, которые могут произойти из-за вызова других функций в ее теле, и должна уметь их все обрабатывать хотя бы на уровне catch(Exception $ex){$log->write($ex->Message);}. Это просто правило хорошего тона. Еще правило хорошего тона требует, чтобы запись в лог шла на самом верхнем уровне программы, когда уже точно исключение либо выбрасывается пользователю, либо просто пожирается.

        Если функция не может обработать исключение — она перебрасывает его с помощью throw.

        Исключения — это еще один способ возврата значения из функции, при этом подобное «значение» всегда означает, что что-то идет не так.
          0
          Исключительная ситуация — это любая ситуация, когда поведение программы отличается от нормального. В том числе, и ввод неверного логина и пароля.

          Так всё-таки, ввод (!) логина и пароля — это поведение программы? Или пользовательское действие?

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

            То есть, чисто формально, конкретный наш пример следует рассматривать так:
            1. Пользователь должен ввести логин и пароль.
            2. Логин и пароль могут быть введены некорректно — надо предусмотреть фильтрацию.
            3. Логин и пароль могут быть введены неверно — надо предусмотреть код возврата.
            4. Логин и пароль могут быть не обработаны из-за серверной ошибки — надо предусмотреть исключение.

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

            Логично, что все. Почему?

            Потому что во всех случаях у нас одинаковое поведение — показать пользователю жуткое окно и редиректуть его для повторного ввода (если возможно, если сервер не упал).

            Разделяя сущности, мы придем к дублированию кода. Наоборот, выкидывая исключение на каждый из типов, мы делаем поведение более общим и не теряем возможность расширения.
              +1
              Я с вами согласен. Вообще, по-моему, использование кодов возврата в эпоху освоения космоса и дешевого интернета — дичь. Естественно, под «кодом возврата» я подразумеваю неочевидные данные. Например, такая функция (довольно часто раньше я так писал):

              bool login(username, password)…

              Что нам говорит код возврата? «Логин не удался». Никакой конкретной информации. А уж конструкции вида if (! login())… еще сильней добавляют туману.

              Другое дело, когда «код возврата» — суть некое смысловое значение (например, int getHttpError() ...).

              Поэтому, с моей точки зрения, исключениям — быть. Единственное, что неудобно — это отсутствие в пыхе возможности спецификации исключений, наподобие ветки throw в C++:

              void f() throw (exception1, exception2) {… }

              Приходится спасаться тегами PHPDocumentor'а, что все-же не так удобно.
                0
                В C# точно так же, кстати. XML-теги спасают.
                  –1
                  это вы — дичь, а нормальные люди пишут чекеры и хранят стэки возвращаемых данных

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

                  а уже внутри — ловятся ошибки, пишутся номера ошибок, номера пишутся в класс ошибок, там преобразуются в мессаги и xajax-ом аппентядтся в афтер лабелы для полей

                  все-таки, имхо, «исключение» и «правило» — разные вещи.
                  проверка логина — это правило, которое должен соблюсти пользователь.
                  а исключение — это если, например, он пытается взломать сайт. подставляет всякие символы и тд…

                  ну даже по логике русского языка «правило» и «исключвение»…
                    0
                    >проверка логина — это правило, которое должен соблюсти пользователь.
                    >а исключение — это если, например, он пытается взломать сайт. подставляет всякие символы и тд…

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

                    Как разруливаем? А главное как отличаем «правило» от «исключения».
                    0
                    а вы помните, как работает throw в плюсах? тут Вам не джава, знающие люди советуют не пользоваться этой конструкцией.
                    0
                    Но можно сделать намного проще, и мне кажется, логичнее. Обрабатывая все сообщения к пользователю через исключения (что, часто, очень удобно)

                    1. Пользователь должен ввести логин и пароль — throw(«Необходимо ввести логин и пароль», E_USER_NOTICE);
                    2. Логин и пароль могут быть введены некорректно — throw(«Не корректный логин или пароль», E_USER_WARNING);
                    3. Логин и пароль могут быть введены неверно — throw(«Не верно введён логин или пароль», E_USER_WARNING);
                    4. Логин и пароль могут быть не обработаны из-за серверной ошибки — throw(«Ошибка на сервере», E_USER_ERROR);

                    Естественно, на константе нотис — просто сообщение, на константе варнинг — отмена действия и предупреждение, на константе еррор — стандартное сообщение об ошибке на сервере, просьбе не волноваться и емайл или смс админу.

                    Можно написать с десяток своих классов, наследником Exception и как в языке java разруливать их.

                    У исключений уйма применений и они достаточно удобны, когда знаешь как ими пользоваться.
                      0
                      А с каких пор сообщения типа notice и warning должны прерывать поток выполнения и сворачивать стек? исключения не могут быть использованы для таких сообщений
                        0
                        Простите, я не совсем вас понимаю.

                        Исключения не прерывают выполнение, обычно… Это да… Но если у вас свой обработчик «error_handler», то вы можете и прервать. Я говорил именно про этот случай.

                        Почему исключения не могут использоваться для этих целей?

                        Можно написать «class ExceptionUserError extend Exceptions {}» и использовать его для обозначения ошибок или неверно введённых данных от пользователя.

                        Почему нет?

                        PS Просто вам кажется что идеалогически исключения должны работать лишь там, где произошла действительная ошибка. Что вообщем-то правильно, но не всегда удобно.
                          0
                          Можно сделать все что угодно и как угодно. Но вы ведь придерживаетесь каких-то принципов, правил и идиом при написании программ? Так вот, исключения — для исключительных ситуаций — это принцип и правило и идиома :).

                          Исключение прерывает нормальный поток выполнения программы и сворачивает стек к близжайшей точке, где возможна обработка этого же исключения. Но логика сообщений notice и warning не подразумевает прерывание нормального потока выполнения программы. Именно поэтому использовать исключения для этих целей не нужно
                            0
                            1. Да, мне тоже очень нравится когда код предсказуем. Тут я с вами не хочу даже спорить. Но я не изобретаю велосипед, я лишь немного «нестандартно» использую исключения.

                            2. Попробуйте такой «финт ушами».
                            set_error_handler("UserErrorHandler");

                            function UserErrorHandler($errno, $errstr, $errfile, $errline){
                            switch ($errno) {
                            case E_USER_ERROR:
                            trigger_error("*USER ERROR* [$errno] $errstr
                            \n".
                            " User error on line $errline in file $errfile
                            \n");
                            exit(1);
                            case E_USER_WARNING:
                            print("*USER WARNING* [$errno] $errstr
                            \n".
                            " User warning on line $errline in file $errfile
                            \n");
                            break;
                            case E_USER_NOTICE:
                            print("*USER NOTICE* [$errno] $errstr
                            \n".
                            " User notice on line $errline in file $errfile
                            \n");
                            break;
                            }
                            return true;
                            }



                            PS Да, я понимаю что это идеологически не верно, но чёрт возьми, на мелких проектах это очень удобно :)
                              0
                              Главное, чтоб то, что удобно на мелких проектах не вошло в привычку.
                      0
                      Нелогично. Исключение, как средство сообщения об исключительных ситуациях должно использоваться только в последнем случае. Во-первых — потому что такова суть исключений, во-вторых, потому что некорректный ввод не является исключительной ситуацией (это вполне ожидаемая ситуация). И в-третьих — потому что поведение все таки может быть разное: самый простой пример — только в последнем случае мы пишем в лог о серверной ошибке, для того, чтобы позже с ней разобраться
                    +7
                    >перебрасывает его с помощью throw
                    еще надо отметить, что перебрасывать надо именно само исключение, а то некоторые говнокодят catch (Exception $e) {throw new Exception($e->getMessage());}
                      +1
                      А концепции inner exception как в .NET, в PHP нету?
                        0
                        дотнетом вообще не владею.
                        это оно? it.toolbox.com/blogs/coding-dotnet/innerexception-14200
                        если я правильно понял, то это хранения одного эксепшена в другом, что можно вполне организовать и на пхп.
                        только не запутывание кода ли это? если есть, например, 3 уровня, 1й ловит второй, а 2й — 3й, и каждый перебрасывает свой эксепшн, то 1й уровень о 3м знать не должен, а то банально инкапсуляция нарушается
                          +1
                          Не совсем, все несколько хитрее.

                          Оборачивать можно внутренние эксепшены в том случае, если их выбрасывание наружу ничего не скажет о сути произошедшей ошибки. Например, если у нас в процессе логина вычисляется какой-нибудь хитрый хеш, и оттуда появляется DivisionByZeroException — мы не будем выбрасывать его наружу (какое нафиг деление на ноль в логине?) — мы обернем его в FaultAutentificationException с пояснением и выкинем.
                            0
                            а какая польза для верхнего уровня от этого? или там как-то автоматически разворачивается стектрейс?
                              0
                              Исключительно в прозрачности обработки исключительны ситуаций.
                          0
                          Если даже и нет, Вы можете создать свой класс, наследованный от Exception, который будет в конструкторе принимать вложенное исключение.
                          Мне вот больше интересно, а в PHP можно получить стектрейс исключения?
                          //
                          (я тоже .NET разработчик)
                            0
                            а, наверное, getTrace() как раз и делает то, о чем я говорю.
                      +4
                      В общем то статья не о PHP, так как стратегия обработки исключений одинакова для многих языков.
                      А вообще спасибо, для себя много не узнал нового, но для других будет очень полезно.
                        0
                        А как кстати с производительностью при перехвате исключений? как будет быстрее вернуть какой-то параметр и обработать его или словить исключение?
                          0
                          Быстрее вернуть параметр, естественно. Исключение — это медленно.
                            0
                            М… это в php так? я могу сказать что в питоне — если есть часто вызываемая ф-я где вы время от времени(не очень часто) бросаете исключения и ловите их, то это будет быстрее чем постоянно проверять что же вернула функция.
                              +1
                              Если не часто — то нормально. Просто следует помнить, что исключение не может быть вариантом штатного завершения функции.
                            +3
                            Если у исключения происходят настолько часто, что влияют на производительность — надо менять логику приложения.
                              +1
                              Согласен, сам недавно сталкивался с такой проблемой… главное вовремя понять что исключения не надо пихать во все щели :) с исключениями было 15-20% загрузки процессора, без — ближе к 1%. прочувствуй разницу, как говорится.
                                0
                                Абсолютно согласен, использование исключений должно быть прежде всего уместным.
                            +2
                              +2
                              и ещё с форума, как раз обсуждаем
                              phpclub.ru/talk/showthread.php?s=&threadid=114258&rand=12
                              –6
                              Важно понимать, что механизм исключений по своей сути недалеко ушел от всеми любимого GOTO. На тему «неправильно введённые логин или пароль — это не исключительная ситуация!» — весьма спорное утверждение. Неправильно заполненная форма — это исключительная ситуация или нет?
                                +3
                                кроме как переход в другую точку кода, что ещё у них общего?
                                  –2
                                  А кроме перехода в другую точку кода, в чем их отличие?
                                    0
                                    goto определяет, куда будет передано управление. throw — нет.
                                    с тем же успехом можно сказать, что и любая управляющая структура — тоже недалеко ушла от goto. тот же if — он тоже изменяет течение программы.
                                  +1
                                  Форма — это вообще не ситуация, это набор данных, введённых пользователем.

                                  В случае, если конечно, класс/метод/функция, обрабатывающие эти данные, не способны правильно обработать неверные данные, то для них это исключительная ситуация. Правда, это довольно странно.
                                    0
                                    Пример:

                                    try {

                                    Signup(R(«username», «email», «capcha»))->validate()->register();

                                    } catch (IJsonable $e) {

                                    JSON(Fail($e));

                                    }

                                    Напишите мне это без использования исключений с проверкой состава полей, их содержимого и попыткой создания записи в БД.
                                      –1
                                      да легко %-)

                                      $user->assign( array('usrname','email','captcha'), $request )->register()->log->success
                                      and $response->content= array( 'message' => 'registered', 'user' => $user )
                                      or $response->content= array( 'message' => 'error', 'log' => $user->log )
                                      ;
                                  0
                                  Пардон, а Data_Access_Exception — это какой стандарт именования функций?
                                  0
                                  я такого мнения что исключения нужно использовать только тогда когда в программе происходит ошибка коотрая «никогда» не должно произойти — вот это исключительная ситуация. Остальное все можно обработать на уровне кодов ошибок и тд

                                  Например, зенд фреймворк может использовать xml файл как конфиг для подключения к базе данных, если файла нет (а это идиотизм, ведь без него о подключении к базе не может быть и речи и он должен быть всегда) — это исключение, точно так же как и ошибка подключения к базе данных.

                                  Однако если у нас помер запрос в методе query (ну вот кто-то забыл отфильтровать кавычки), то это просто внештатная ситуация, можно вернуть например false и выдать ошибку юзеру мол извините, на сервере проблемы. однако это ни в коей мере не мешает работе приложения, оно просто уйдет в другую ветку логики
                                    0
                                    А если уходить некуда? Нужно выкидывать исключение :)
                                    +1
                                    Согласен.
                                    И применимо это не только для PHP, но и для других языков, работающих с исключениями.
                                      +2
                                      У вас тут одна ошибка. Имея названия ошибок: Application_Exception, Logic_Exception, Data_Access_Exception, Security_Exception. То получается помойка из папок, если придерживатся Автолоада классов. И автокомплит будет офигительно криво работать, гораздо удобнее когда:
                                      Exception_Logic Exception_Application. — тогда всегда всё будет в одной папке, в автокомпликте будет удобнее.
                                        0
                                        Большое спасибо, Вы правы.
                                          0
                                          Лично мне удобнее классы исключений определять там, где они используются. Например, Model_Exception может выбрасываться в классе Model_User или Model_Product_Type. А именование исключений в обратном порядке вынуждает меня дублировать структуру каталогов. Мне это неудобно.
                                            0
                                            Гм, тут немного другая мысль. и мы об одном и том же. Moldel_Exception хорошо, но допустим у нас есть Logic и File. тогда у нас будет Model_Excpeption_Logic и Model_Excpeption_File
                                              0
                                              Вот с этим я с некоторой натяжкой могу согласиться. Хотя в моей практике такого небыло. Exception всегда на нижнем уровне. Но и такого, что в каталоге только Exception, тоже небыло.
                                                0
                                                Ну да, на практике у меня например Mapper_DataException Mapper_AuthException Mapper_AggregateEmptyException
                                                  0
                                                  Ну а тут мне нечего возразить :)
                                            0
                                            лучше просто дождаться 5.3 :)
                                              0
                                              А чего в 5.3 такого важного случится что можно забить на наименования?
                                                0
                                                случатся неймспейсы
                                                  0
                                                  И чем они спасут от говно-имён?)
                                                    0
                                                    Как ни крути, но вряд ли люди будут создавать неймспейсы Application, Logic, Data\Access только для того, чтобы сложить в них исключения.
                                                      0
                                                      Нет пределу человеческому гению =)
                                            –3
                                            Так ли часто мы пишем библиотеки на PHP? Столько уровней, прямо операционная система, а не сайт.
                                            В 90%+ процентах случаев паттерна MVC с головой, а необходимые библиотеки давно написаны.

                                            И хотя статья правильно описывает работу с исключениями, но она больше бы подошла к разработке на java а не php. Особенно, учитывая еще и тот вариант, что в PHP есть fatal_error-ы, которые не являются исключениями, не перебрасывваются никуда и тупо стопорят исполнение программы на месте. Поэтому исключения в php сейчас выглядят как костыль, который есть для галочки.
                                              0
                                              Оставшиеся 10 — самые интересные ;)
                                              0
                                              Ещё добавлю из практики применения эксепшенов у меня в проекте.
                                              1. Эксепшн валидации данных(поле не заполнено, емейл кривой)
                                              2. Эксепшн данные не найдены.(так показываем 404.)
                                              3. Эксепшн доступа к данным(403 =)
                                              4. Эксепшны отдельных модулей(СМСку нельзя отправить, ОпенАйди лажает. итп)
                                              5. Фатальные ошибки.
                                                0
                                                у тебя все формы состоят из одного единственного поля, что ты кидаешься исключениями?
                                                  0
                                                  Нет, я кидаю исключение, в котором есть перечисление всех некорректно заполненых полей с типом ошибки. там есть метод getErrors(); который возвращает ассоциотивный массив в ключе имя поля, в значении — тип ошибки. Очень удобно.
                                                    0
                                                    ещё есть аутентификация, права, целостность данных в базе и прочие необходимые проверки. они тоже примёрживаются в одно исключение?
                                                      0
                                                      К словам дорогой мой придераешься. Пишу сейчас пост о том как Я использую исключения. Одним эксепшеном ошибки одного типа. В данном случае это ошибки формата.
                                                        0
                                                        «одного типа» — понятие абстрактное.
                                                        при формировании респонса нужно выдавать все ошибки (строка вместо числа, идентификатор уже занят, нет прав на использование хтмл), а не только первого попавшегося типа…
                                                          0
                                                          Как же хочется вам поспорить. то что вы перечислили — это ошибка входных данных, данные нас не устраивают из-за того что формат не тот. или айдишник занят, или хтмл использовали — а прав нету.
                                                          Небыло бы прав на создание сущности — да, это уже другой эксепшн. а всё что вы перечислили у меня в проекте перекидывается всё в одном эксепшене и это нормально и удобно.
                                                            0
                                                            нет прав на содание сущности — нужно выдавать форму перелогина и ошибки в данных.
                                                    0
                                                    Отличный способ. Кстати говоря, в Symfony, начинаю с 1.1 валидация организована примерно так же.
                                                  0
                                                  Забыл добавить:
                                                  6. Редиректы.
                                                  7. Запрос на HTTP авторизацию.
                                                • UFO just landed and posted this here
                                                    0
                                                    ошибка подключения к базе данных является исключительной ситуацией только для метода подключения.
                                                    зачем высокоуровневому модулю знать обо всех низкоуровневых, и исключениях, которые могут там возникнуть?
                                                      +1
                                                      Гм-гм… то есть, если к БД подключиться не удалось, уровень работы с БД должен проворчать типа «блин, нет базы. Ну и фиг с ней, будем работать на файлах и вообще, у меня будет своя база с блэкджеком и шлюхами!» Так что ли?
                                                        0
                                                        да, представь себе. приложение не должно падать только от того, что одна база вдруг отвалилась.
                                                          0
                                                          А мне казалось, что это зависит, в первую очередь от контекста использования. При чтении данных такой финт еще может прокатить, но при модификации — уж лучше сразу под поезд.
                                                            0
                                                            ага, расскажи это пользователю, который 30 минут набирал текст…
                                                      +2
                                                      Эх, хороши исключения, да вот в PHP они реализованы с изъяном — библиотечные функции, а так же различные исключительные ситуации вроде 1 / 0 или null->foo() реализованы не с помощью исключений. Конечно, есть способ с set_error_handler и выкидыванием, но опять же, он почему-то не всегда работает. Например, в том же случае с null->foo обработчик, установленный с помощью set_error_handler почему-то не срабатывает. А это значит, что вместо исчерпывающего стектрейса я получаю невнятное сообщение всего лишь с одним номером строки.
                                                        –3
                                                        Статья хорошая.

                                                        Расскажу свой способ определения, когда стоит выбрасывать исключение а когда нет: когда я пишу код, то предполагаю что все методы должны возвращать только один любой тип данных (сами определяем какой: Объект определенного типа, массив, число, строку и т.д.) Если по каким-то причинам в методе нужно вернуть еще что-то, или вернуть другой тип данных — выбрасываем исключение
                                                          +1
                                                          Бредовый код. Выходные данные должны быть всегда те, которые были запрошены. Исключение = прерыванея выполнения кода. Если вы возвращаете данные из методов методом исключений — то это, простите, говнокод.
                                                            0
                                                            Интересно, если нужно ролбэкнуть транзакцию, вы тоже плюете и заканчиваете выполенение кода? Не смешите, исключения выбрасываются для того чтобы их обработать.

                                                            По поводу «данные должны быть всегда те, которые были запрошены» — метод должен возвращать тот тип данных, который он продекларировал, а не менять его в зависимости от настроения. Если каждый метод в вашем коде возвращает разные типы данных, то лучше подумайте как этого избежать. Тогда отпадет вопрос и с исключениями
                                                              0
                                                              Переформулирую «Исключение = прерыванея выполнения кода в текущего алгоритма», чтобы потом выше его поймать, и сделать то, что надо. В моём коде славо богу такого нет, но в пхп есть, и с этим ничего не поделаешь. например регулярные функции. Хочешь с офсетом, хочешь сгрупперованное по патерну. а хочешь по вхождениям. Но этим не стоит злоупотреблять.
                                                            –1
                                                            А с параметрами передаваемыми по ссылке или out параметрами методов вы не знакомы?
                                                              –1
                                                              вы в мой профиль заглядывали, дядя?
                                                          0
                                                          Спасибо, статья действительно очень познавательна, но есть вопрос:
                                                          Методы класса не должны перехватывать исключения, сгенерированные другими методами этого же класса. Библиотека вообще ничего не должна знать о том ...

                                                          Вот смотрите, у меня есть класс, который читает информацию из файла. Если, вдруг, что-то там происходит, я вызываю исключительную ситуацию. Но тут вопрос, если не обрабатывать её просто в классе, типа:
                                                          try
                                                          readData
                                                          except
                                                          print error
                                                          А если отлавливать исключение каждый раз, когда нужно прочитать какой-то параметр из файла? Как здесь быть: Оставить отловление исключений в том классе, или испортить читабельность кода?
                                                            +1
                                                            Я бы еще добавил рекомендацию написать для приложения обработчик Unhandled Exceptions, который обязательно должен вести лог необработанных исключений. Часто об этом забывают поначалу.
                                                              0
                                                              сорри, это не ответ, я по ошибке не в корень запостил.
                                                                0
                                                                Ничего =). Зато я на него внимания обратил и действительно задумался. Спасибо.
                                                              0
                                                              Я тут написал «Исключения. Где я их использую», кармы на перенос в блог не хватет, понравится — перенесу.
                                                                0
                                                                Небольшой но содержательный и полезный пост! Очень здорово было бы рассказать о применении эксцепшенов в «рядовых» ситуациях (ну в стиле «Избавляемся от «if(!$db) die('...');»», чтобы задать вектор мышления у людей, не пользовавшихся ими до этого.
                                                                  0
                                                                  для этого достаточно почитать документацию.
                                                                    0
                                                                    Не думаю, что достаточно — хоть там и есть примеры, но…
                                                                    Всё приходит с опытом, и если он есть, почему бы им не поделиться?
                                                                  +2
                                                                  В крупном приложении необходимо использовать свои собственные классы исключений (унаследованные от встроенного Exception)

                                                                  В PHP есть не только встроенный Exception, но и еще много разных Excception'ов. В числе прочих там есть и LogicException. И свои классы исключений иногда лучше наследовать от подходящего базового класса (ну и, само собой, вовсю использовать собственно все предоставляемые «бесплатно» встроенные классы, а не только Exception).

                                                                  Only users with full accounts can post comments. Log in, please.