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

Пока досконально разбираюсь в эксепшенах и загрузке файлов. пробелы, отступы это так, если к слову придется) А что там со звоном не так? Языки-то примерно одинаково развиваются...
Что со звоном? я не встречал ни в struts ни в spring ни в jsf изключений по вводу со стороны пользователя,
смысел в том, что из-за ввода данных, программа может не коректно закончить работу, (пользователь обратился на несуществующий ресурс), - "Контролируемые исключения"
 
Ок. А загрузку файла пользователем можно считать его вводом? И как она должна обрабатываться, если размер файла оказался больше допустимого или закончилось место на диске? Тут об ошибке нужно сообщить пользователю, но и программист так же должен знать о закончившемся месте...
 
можно... никто не запрещает тебе этого делать, все в твоих руках,... садись и пиши уже!
нужно показать ошибку? покажи!... как ты это реализуешь, за рамками этого разговора.
нафига программисту знать, что у васи пупкина закончилось место на диске?
 
Ну, если место не у Васи Пупкина закончилось, а на всем сервере, то знать надо. А так пишу уже давно, даже написал и уже по второму разу переписываю)
 
когда место на диске закончилось, уже слишком поздно, чаще это нужно знать месяца за полтора!
 
ахах - было у меня такое... проспал =)
на панике - быстрее логи старые вычищать
 
да да, и кэш удалять, и еще чтонить ненужное, а после вдруг вспоминаешь, что есть другой неиспользуемый диск, монтируешь его как одну из подпапок хранилища, и гордо идешь заявлять начальству, что пораб задуматься, мол мне пришло сообщение заранее
 
Напишу, пока в голове держится. Разобрался зачем нужны throw Exception. Нужны они исключительно в ситуациях, когда пользователь не может исправить ошибку. Загружен файл не того формата, закончилось место на диске или оборвалось соединение с интернетом, может пользователь это исправить? Очевидно, может залить другой файл, удалить ненужные, перезагрузить роутер. Такие ошибки следует выводить через массив $errors, с пояснением как устранить проблему и даже переводом на язык пользователя. Если же проблема в том, что нет коннекта с БД или сломалась функция, то пользователь все-равно ничего поделать не сможет. Для таких технических ошибок и нужны throw Exception
 
Про trigger_error очень спорно в этой статье. Если не удается открыть файл, который должен быть на месте, что это, если не исключение? Какой смысл продолжать работу, если не удалось прочитать файл с необходимыми для продолжения работы данными? Так что лучше заворачивать php-ошибки в исключения.

Про исключения в целом правильно: ловить их надо ровно в том месте, где можно сделать что-то осмысленное (например, rollback). Если ничего осмысленного сделать нельзя - пусть уходит наверх, до показа 500-й.
 
А как определить поправима ошибка или нет? Исходя из этой статьи если у нас нет резервного сервера БД, значит непоправима и исключения бросать не стоит. ОК. Но тут мы взяли и дополнили систему сервером БД и что, все ошибки на исключения придется переписывать и так после каждого апдейта системы обработки ошибок?
 
Silentland
Не, ты не понял. Исключения бросаем на все, что являтся, как ты говоришь, технической ошибкой (а не ошибкой валидации и т.д.).
Если есть место, где можем проблему исправить - ловим там.
Если нет - пусть летит наверх.
 
Приведу пару примеров осмысленного 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 это работает только со своими исключениями или исключениями, которые кидают библиотеки.
 
Silentland
Никаких особенных и отличительных ошибок или исключений не бывает. Там статья какая-то бородатая и перекосяченная, вроде бы и автор не глуп, но и текст "не айс", запутывает. Это часто встречается.

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

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

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

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

В некоторых случаях вполне нормально расширять исключения. Например, не вижу ничего плохого в throw new Http\Error(404).
 
Lionishy
В целом, да, но
разделять исключения-неожиданные (форс мажор или ошибки) и исключения-контрактные (то, что и называют обыкновенно исключительными ситуациями).
если ты про catchable exceptions в java, то само такое разделение многие (я тоже ;) ) считают одной из крупных ошибок проектирования джавы.
 
fixxxer
А откуда ты знаешь, исключительная это ситуация или нет? И, если уж на то пошло, откуда модель знает, пользовательский это ввод или нет? Метод принимает аргументы, а откуда они взялись - он же не должен знать? Мне кажется, я реально чего-то не понимаю.
 
Сверху