Фатальные ошибки и функция die
Сейчас мы ненадолго отвлечемся. Нам понадобится материал, не связанный напрямую с темой ввода/вывода (и не ограничиваемый ею). Речь идет о том, как прервать работу программы до ее ожидаемого завершения. Когда в Perl происходит фатальная ошибка (например, при делении на нуль, использовании некорректного регулярного выражения или вызове пользовательской функции, которая не была объявлена), программа прерывает свое выполнение и выдает сообщение с описанием причин ошибки. Но эта функциональность доступна и для разработчика в виде функции die, что позволяет ему создавать свои собственные фатальные ошибки.
Функция die выводит сообщение, переданное при вызове (в стандартный поток ошибок, куда должны поступать такие сообщения), и обеспечивает выход из программы с ненулевым кодом завершения. Возможно, вы и не знали об этом, но каждая программа, выполняемая в UNIX (и многих других современных операционных системах), обладает числовым кодом завершения, который сообщает, успешно была выполнена программа или нет. Программы, запускающие другие программы (например, утилита make), по коду завершения проверяют, правильно ли прошло выполнение. Код завершения состоит всего из одного байта, и в него трудно уместить сколько-нибудь подробное описание. Традиционно значение 0 считалось признаком успешного выполнения, а любое ненулевое значение – признаком ошибки. Допустим, код 1 может означать синтаксическую ошибку в аргументах команды, 2 – ошибку на стадии обработки, 3 – ошибку при поиске конфигурационного файла; конкретные значения определяются для каждой команды. Но значение 0 всегда означает, что выполнение прошло нормально. Если код завершения указывает на возникшую ошибку, программа (например, make) знает, что к следующему этапу переходить не следует. Таким образом, предыдущий пример можно переписать в следующем виде:
if ( ! open LOG, ">>logfile") {
die "Cannot create logfile: $!";
}
Если вызов open завершается неудачей, die завершает программу и сообщает, что создать файл журнала не удалось. Но что делает $! в сообщении? Это системное описание ошибки в форме, понятной для человека. В общем случае, когда система отказывается выполнить запрос программы (например, открыть файл), в переменной $! указывается причина (например, «отказано в доступе» или «файл не найден»). Эту же строку можно получить при помощи perror в языке C или других языках. В Perl это сообщение содержится в специальной переменной $!. Желательно включать эту переменную в сообщение; она поможет пользователю разобраться в том, что же было сделано неправильно. Но если die применяется для обозначения ошибок, происходящих не в результате ошибки по системному запросу, не включайте переменную $! в сообщение; обычно в ней будет содержаться постороннее сообщение, оставшееся от внутренних операций Perl. Полезная информация останется только после ошибок, происходящих при выполнении системных запросов. При удачном завершении запроса никакой полезной информации здесь не останется.
Есть еще одна операция, которую die автоматически выполнит за вас: к сообщению присоединяется имя программы Perl и номер строки, что позволит вам легко определить, какая команда die в программе ответственна за преждевременный выход. Сообщение об ошибке из предыдущего кода может выглядеть так (предполагается, что переменная $! содержит сообщение permission denied):
Cannot create logfile: permission denied at your_program line 1234.
Весьма полезные сведения – обычно нам хочется получать в сообщениях об ошибках больше информации, чем мы сами в них включаем. Если вы не хотите выдавать номер строки и имя файла, проследите за тем, чтобы «предсмертное сообщение» завершалось символом новой строки:
if (@ARGV < 2) {
die "Not enough arguments\n";
}
Если при вызове передано менее двух аргументов командной строки, программа сообщит об этом и завершится. В сообщении не приводится ни имя программы, ни номер строки, так как для пользователя номер строки бесполезен (в конце концов, это именно его действия стали причиной ошибки). Запомните простое эмпирическое правило: символ новой строки используется в сообщениях, указывающих на ошибку пользователя, и опускается там, где ошибка может быть исправлена во время отладки. Всегда проверяйте возвращаемое значение open, так как оставшаяся часть программы зависит от его успеха.