Исключения (Exception) (Рейтинг: +5)

Печать RSS
Общие сведения об исключениях
До появления ООП существовало два подхода к обработке ошибок в программе:
1. Возврат кода ошибки из вызываемой функции или программы;
2. Возврат имени ошибки из вызываемой функции или программы.
Как видно, оба подхода страдают от того, что имя или код ошибки малоинформативны без описания. Запись ошибки типа: Ошибка 1234 – мало о чем говорит отладчику и требует постоянного обращения к документации.
ООП предоставило другой способ описания ошибок. Сегодня ошибка, ее код, описание, даже причина, инкапсулируется в объект, называемый Исключением. Данное исключение создается и передается вверх по стеку вызова, «убивая» все на своем пути, пока оно не будет обработано.
Сегодня исключения позволяют работать с ошибками как с объектами, что позволяет быстро и эффективно отлаживать программные продукты.

Иерархия исключений
Из того, что исключения являются объектами, можно сделать вполне обоснованный вывод, что классы исключений могут быть выстроены в иерархии наследования, что и реализуется во всех современных языках, поддерживающих ОО парадигму, в том числе и PHP.
В PHP можно выделить следующую иерархию:
• Исключения времени компиляции – данный вид исключений используется для информирования об ошибках, обнаруженных на этапе компиляции PHP скриптов;
• Исключения времени выполнения – данный вид исключений используется для информирования об ошибках, обнаруженных на этапе выполнения (интерпретации) PHP скриптов. Это наиболее распространенные, часто используемые и важные исключения ;
• Логические исключения – данный вид исключений используется для информирования об ошибках, связанных с логикой программы. На пример обращение к несуществующему элементу массива или попытка записи в несуществующий файл.
Если взглянуть на сторонние программные продукты, то можно заметить что практически любой программный пакет включает собственный набор, специфичных именно для него, исключений. На пример пакет для работы с файловой системой чаще использует исключения типа: Отсутствие файла, Блокировка файла, Ошибка адреса в файловой системе – и так далее. Это очень важное решение, создавая новые пакеты, вам так же придется и определять новые типы исключений. Для чего это нужно? На собственном опыте скажу, что использование на протяжении всей программы одного вида исключений, на пример
<?php
throw new Exception(‘Описание ошибки’)
рано или поздно приведет к тому, что выбрасывание исключения заставит вас перерывать кучу кода, чтобы понять смысл и содержания описываемой ошибки. С другой стороны, если вы увидите исключения типа: FileNotExistsException, то сразу будет понятно, что ошибка связана с отсутствием требуемого файла, а если проследить стек, то легко локализовать и исправить ошибку.
Запомните! Используйте собственные типы исключений для описания различных видов ошибок. Не стоит полагаться только на стандартные исключения.
Чтобы определить собственный тип исключения достаточно создать подкласс одного из классов исключений. На пример если вам нужно создать обозначенное ранее исключение FileNotExistsException, то можно реализовать его с помощью следующего класса:
<?php
class FileNotExistsException extends \RuntimeException{
}
Заметьте, что я наследую не от класса Exception, являющегося корневым в иерархии исключений, а от класса RuntimeException, который так же является дочерним по отношению к классу Exception, но при этом выделяет такие исключения, которые выявляются на этапе выполнения. Это означает, что исключение типа FileNotExistsException может быть выброшено только на этапе выполнения, но не компиляции.
Запомните! Чтобы правильно строить собственные иерархии исключений, вам необходимо изучить существующие в PHP иерархии и выбирать, к какой ветке будут относиться ваши иерархии.

Когда и как следует использовать исключения
• Используйте выброс исключения тогда, когда метод получает неожиданные данные («мусор») на вход. На пример метод получает в качестве аргумента массив, когда ожидается число;
• Используйте выброс исключения тогда, когда метод не может продолжить выполнения в связи с недостатком данных. На пример метод не может произвести запись в файл, так как файла не существует;
• Используйте выброс исключения тогда, когда вы запрещаете использование родительского метода в дочернем классе;
• Используйте выброс исключения тогда, когда вы хотите сообщить, что некоторый метод устарел и использование его запрещается. Это позволит выявить использование устаревших методов в коде при переходе на новую версию продукта;
• Создавайте стек исключений передавая в качестве третьего аргумента конструктора исключений то исключение, которое явилось причиной создаваемому исключению. На пример если метод не может создать файл по причине синтаксической ошибки в имени файла, то можно обернуть исключение SyntaxException в исключение FileException. В этом случае вам будет понятно, что ошибка была вызвана синтаксисом;
• Давайте осмысленные имена классом исключений. Более детализованные конкретным типам исключений, и более абстрактные обобщающим типам. На пример для описания исключения, вызванных файловой системой можно использовать абстрактный класс FileSystemException, а для описания исключений, вызванных отсутствием требуемого файла или каталога в файловой системе, можно использовать класс ComponentNotExistsException который будет являться подклассом класса FileSystemException.

Когда и как не следует использовать исключения
• Не используйте исключения, если возврат метода достаточен для описания результата и никаких исключительных ситуаций не найдено. На пример для метода create, создающего файл с данным именем, можно использовать данные возврата: true – если файл удачно создан и false – если создание файла не выполнено в связи с некоторой ошибкой, как на пример существование файла с тем же именем. Здесь вполне можно обойтись без исключений;
Запомните! Решить когда нужно использовать исключения, а когда можно обойтись возвращаемыми данными вам придется самостоятельно. Придерживайтесь следующего правила, если вам требуется знать причину ошибки в методе, то используйте исключения, если же причина вам не важна, а нужно знать только выполнен ли метод или нет, то используйте данные, возвращаемые методом.
• Не используйте исключения для реализации бизнес-логики приложения. На пример не следует использовать конструкцию try…catch как эквивалент конструкции if;
• Постарайтесь не использовать выброс исключений в конструкторах классов, это может привести к утечкам памяти;
• Наличие сложной, многоуровневой иерархии исключений программного пакета обычно свидетельствует об ошибочной архитектуре. Для программного пакета обычно достаточно одного-трех уровней иерархии исключений.

Классы исключений SPL
• LogicException – свидетельствует об ошибке в логике программы.
o BadFunctionCallException – свидетельствует об обращении к неопределенной функции или об отсутствии требуемых аргументов;
 BadMethodCallException – свидетельствует об обращении к неопределенному методу или об отсутствии требуемых аргументов;
o DomainException – свидетельствует о том, что выполнение программы не придерживается заданной области данных;
o InvalidArgumentException – свидетельствует о том, что функцией или методом был получен аргумент неожиданного типа или формата;
o LengthException – свидетельствует об ошибке длины;
o OutOfRangeException – свидетельствует о том, что была произведена попытка выхода за границы множества.
• RuntimeException – свидетельсвует об ошибке выполнения программы.
o OutOfBoundsException – свидетельствует о том, что была произведена попытка обращения к элементу множества по неверному ключу;
o OverflowException – переполнение контейнера;
o RangeException – ошибки диапазона;
o UnderflowException – свидетельствует о попытке удаления элемента из пустого множества;
o UnexpectedValueException – свидетельсвует о том, что получены данные несоответствующие ожидаемым.
Запомните! Если для описания ошибки можно воспользоваться существующим классом исключений, то следует сделать это.

Пример иерархии исключений
Приведу пример моей иерархии исключений, которые определены в программном пакете взаимодействия с файловой системой:
• ComponentDuplicationException – данное исключение свидетельствует о том, что выполнение метода приведет к созданию двух компонентов с одинаковым именем в контексте одного каталога;
• LockException – данное исключение свидетельствует о том, что невозможно получить поток из-за блокировки;
• NotExistsException – данное исключение свидетельствует о том, что одного из необходимых компонентов файловой системы не существует;
• UpdatingRoodException – данное исключение свидетельствует о том, что предпринята попытка изменения корневого каталога.
Добавил:
Рейтинг: +5
Просмотры: 1876
Комментарии (0) »