Тупые вопросы про Exception

WMix

герр M:)ller
Партнер клуба
Пока досконально разбираюсь в эксепшенах и загрузке файлов. пробелы, отступы это так, если к слову придется) А что там со звоном не так? Языки-то примерно одинаково развиваются...
Что со звоном? я не встречал ни в struts ни в spring ни в jsf изключений по вводу со стороны пользователя,
смысел в том, что из-за ввода данных, программа может не коректно закончить работу, (пользователь обратился на несуществующий ресурс), - "Контролируемые исключения"
 

Silentland

Новичок
Ок. А загрузку файла пользователем можно считать его вводом? И как она должна обрабатываться, если размер файла оказался больше допустимого или закончилось место на диске? Тут об ошибке нужно сообщить пользователю, но и программист так же должен знать о закончившемся месте...
 

WMix

герр M:)ller
Партнер клуба
можно... никто не запрещает тебе этого делать, все в твоих руках,... садись и пиши уже!
нужно показать ошибку? покажи!... как ты это реализуешь, за рамками этого разговора.
нафига программисту знать, что у васи пупкина закончилось место на диске?
 

Silentland

Новичок
Ну, если место не у Васи Пупкина закончилось, а на всем сервере, то знать надо. А так пишу уже давно, даже написал и уже по второму разу переписываю)
 

WMix

герр M:)ller
Партнер клуба
когда место на диске закончилось, уже слишком поздно, чаще это нужно знать месяца за полтора!
 

Redjik

Джедай-мастер
ахах - было у меня такое... проспал =)
на панике - быстрее логи старые вычищать
 

WMix

герр M:)ller
Партнер клуба
да да, и кэш удалять, и еще чтонить ненужное, а после вдруг вспоминаешь, что есть другой неиспользуемый диск, монтируешь его как одну из подпапок хранилища, и гордо идешь заявлять начальству, что пораб задуматься, мол мне пришло сообщение заранее
 

Silentland

Новичок
Напишу, пока в голове держится. Разобрался зачем нужны throw Exception. Нужны они исключительно в ситуациях, когда пользователь не может исправить ошибку. Загружен файл не того формата, закончилось место на диске или оборвалось соединение с интернетом, может пользователь это исправить? Очевидно, может залить другой файл, удалить ненужные, перезагрузить роутер. Такие ошибки следует выводить через массив $errors, с пояснением как устранить проблему и даже переводом на язык пользователя. Если же проблема в том, что нет коннекта с БД или сломалась функция, то пользователь все-равно ничего поделать не сможет. Для таких технических ошибок и нужны throw Exception
 

fixxxer

К.О.
Партнер клуба
Про trigger_error очень спорно в этой статье. Если не удается открыть файл, который должен быть на месте, что это, если не исключение? Какой смысл продолжать работу, если не удалось прочитать файл с необходимыми для продолжения работы данными? Так что лучше заворачивать php-ошибки в исключения.

Про исключения в целом правильно: ловить их надо ровно в том месте, где можно сделать что-то осмысленное (например, rollback). Если ничего осмысленного сделать нельзя - пусть уходит наверх, до показа 500-й.
 

Silentland

Новичок
А как определить поправима ошибка или нет? Исходя из этой статьи если у нас нет резервного сервера БД, значит непоправима и исключения бросать не стоит. ОК. Но тут мы взяли и дополнили систему сервером БД и что, все ошибки на исключения придется переписывать и так после каждого апдейта системы обработки ошибок?
 

fixxxer

К.О.
Партнер клуба
Silentland
Не, ты не понял. Исключения бросаем на все, что являтся, как ты говоришь, технической ошибкой (а не ошибкой валидации и т.д.).
Если есть место, где можем проблему исправить - ловим там.
Если нет - пусть летит наверх.
 

fixxxer

К.О.
Партнер клуба
Приведу пару примеров осмысленного catch.

1. Транзакция: если вылетело исключение, делаем rollback, и кидаем исключение дальше.

PHP:
$Db->begin();
try {
    $Db->query($query);
    $Db->query($query2);
    $Db->commit();
} catch (Exception $e) {
    $Db->rollback();
    throw $e;
}
2. Предположим, у нас в бесконечном цикле работает фоновый скрипт, который разбирает какую-то очередь:
PHP:
for (;;) {
    while ($element = $queue->next()) {
        process($element);
    }
    sleep(30);
}
и не хотим, чтобы работа прерывалась при одиночном исключении (ну например временно отвалилось соединение с базой, если попробовать еще раз - само реконнектнется в библиотеке. Или временно потерялась связь с соседним сервером, и т.п.). Тогда можно написать в первом приближении как-то так:

PHP:
define('MAX_EXCEPTIONS', 10);
$exception_counter = 0;
for (;;) {
    try {
        while ($element = $queue->next($element)) {
            process($element);
        }
    } catch (Exception $e) {
        $logger->logException($e);
        if (++$exception_counter > MAX_EXCEPTIONS) {
            $logger->logError('Too many exceptions: ' . $exception_counter . '. Halting');
            break;
        }
    }
    sleep(30);
}
Улучшение - сбрасывать счетчик после того, как в течение некоторого периода времени все хорошо.

3. Приведу пример из python-овского мана, где исключения имеют толковые имена, и являются штатным мезанизмом (в отличие от php с убогими warnings):
PHP:
import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as e:
    print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
Здесь мы можем принять правильное решение в зависимости от типа исключения. Вывод строки, конечно, малосодержателен, но вполне можно представить себе ситуацию, когда эта операция осмысленна. Например, мы импортируем пачку файлов, и в случае ошибки чтения или приведения типов - логируем информацию о том, где была проблема, и продолжаем работу.

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

В php это работает только со своими исключениями или исключениями, которые кидают библиотеки.
 

Lionishy

Новичок
Silentland
Никаких особенных и отличительных ошибок или исключений не бывает. Там статья какая-то бородатая и перекосяченная, вроде бы и автор не глуп, но и текст "не айс", запутывает. Это часто встречается.

В жизни всегда случаются ситуации, когда контракт, заранее сговоренный и подписанный поставщиком и клиентом, оказывается невозможным к исполнению. Это и есть та самая "нештатная ситуация". Как хотите называйте: исключение, ошибка или другая терьям-пам-пация. Однако раз уж она возможно, нужно что-то делать... А вот как конкретно -- это уже вопрос средства языка.
Исключения -- одно из этих средств.

И всё. Сказочки конец.

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

uid

Новичок
fixxxer
Кстати, а почему в мире похапе добавление своих функций и свойств к стандартному классу Exception считается плохой практикой? Можно было бы, например, бросать исключения и при валидации, а там, где надо, доставать из $e подробную информацию. В том же C#, например, исключения довольно часто имеют дополнительные свойства и методы.
 

fixxxer

К.О.
Партнер клуба
uid
Плохой практикой является использование исключений для обработки неисключительных ситуаций. В любом языке.

В случае неисключительной ситуации (скажем, валидация пользовательского ввода), exception - это замаскированный goto, альтернативный control flow, что только все усложняет.

В некоторых случаях вполне нормально расширять исключения. Например, не вижу ничего плохого в throw new Http\Error(404).
 

fixxxer

К.О.
Партнер клуба
Lionishy
В целом, да, но
разделять исключения-неожиданные (форс мажор или ошибки) и исключения-контрактные (то, что и называют обыкновенно исключительными ситуациями).
если ты про catchable exceptions в java, то само такое разделение многие (я тоже ;) ) считают одной из крупных ошибок проектирования джавы.
 

uid

Новичок
fixxxer
А откуда ты знаешь, исключительная это ситуация или нет? И, если уж на то пошло, откуда модель знает, пользовательский это ввод или нет? Метод принимает аргументы, а откуда они взялись - он же не должен знать? Мне кажется, я реально чего-то не понимаю.
 
Сверху