OutOfRangeException и OutOfBoundsException

PHP определяет два исключения SPL для недопустимых ключей:

OutOfRangeException : Исключение, OutOfRangeException при запросе незаконного индекса. Это означает ошибки, которые должны быть обнаружены во время компиляции.

OutOfBoundsException : Исключение OutOfBoundsException если значение не является допустимым. Это означает ошибки, которые не могут быть обнаружены во время компиляции.

Поскольку PHP не является компилируемым языком, различие между временем компиляции и временем выполнения кажется странным, и поэтому мне трудно понять, какое исключение использовать когда.

В настоящее время я понимаю, что нужно бросать …
OutOfRangeException если ключ фундаментально и OutOfRangeException искажен, например, если массив передан как ключ.
OutOfBoundsException если ключ вообще нормально, но не находится в некоторых границах, например, если 100 передано, но 50 – это максимальный ключ.

Правильно ли это понимание?

Хотя PHP не имеет классического «времени компиляции» (или компилятора, который делает много статических проверок, если на то пошло), я бы рассматривал «время компиляции» как «довольно статичный материал, который я делал неправильно при написании кода» и « время запуска ", поскольку" моя логика, ввод или проверка были отключены в какой-то момент ".

Поэтому мое предложение было бы относиться к этому так:

"Compile Time" / "OutOfRangeException" : ошибка всегда может быть исправлена ​​в исходном коде без или с очень малой логикой.

Я всегда беру цифры от 1 до 10, и вы кладете 11


"Run Time" / "OutOfBoundsException" : ошибка связана с неправильным использованием во время выполнения.

Вы создали меня и сказали мне принимать значения от 1 до 5, затем вы помещаете 7. Не вычисляет

или

Вы запрашиваете индекс, которого нет, потому что вы его не поместили, как вы должны


Образец:

Я бы ожидал, что SplFixedArray выкинет OutOfBoundsException потому что его размер является динамическим и может иметь шанс во время выполнения, в то время как я ожидал бы что-то вроде Calender::getMonthName для throw и OutOfRangeException потому что число месяцев определенно фиксировано в «компиляции / записи», время.

Образец объекта массива:

Скажем, $ array – это объект, реализующий ArrayAccess, который вы можете выкинуть OutOfBoundsException в этих обстоятельствах:

 $array['bar']; $array[7]; 

Поскольку значения – это то, что вы могли бы ожидать для ArrayAccess, но это не имеет смысла в случае SplFixedArray (5). Альтернативами было бы DomainException или, возможно, RangeException

OutOfRangeException в этих случаях:

 $calendar->getMonth(15); 

Поскольку для размещения массива или нового класса существует определенный недостаток логики в коде, который обычно возникает из-за простой ошибки «oh, i put in the wrong variable» программиста. Альтернативой (возможно, предпочтительной) будет UnexpectedValueException и старый старый InvalidArgumentException .

Для таких случаев, как:

 $array[array()]; $array[new StdClass]; 

некоторые из альтернативных исключений кажутся более подходящими.

Сравнение с миром Java, на котором исключение использовать, когда не всегда применимы как разработчики Java, имеет проблемы с дополнениями.

Проверено / Непроверено исключение. Со многими людьми, утверждающими, что все, что не является исключением во время выполнения, имеет очень ограниченное использование в Java / не должно использоваться многократно), эти имена потеряли часть своего первоначального значения и намерения.

Мой собственный подход к этому:

LogicException

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

RuntimeException :

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

OutOfBounds

эффективно ИМО, что Википедия определяет как диапазон массива в диапазоне программирования в компьютерном программировании , а именно:

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

Другими словами, когда у вас есть массив с индексами [0,1,2], все, кроме [0,1,2], выходит за пределы. Обратите внимание, что Bounds также могут применяться к другим типам данных, например, попытка получить доступ к 7-му символу в 5-символьной строке также будет OutOfBounds.

OutOfRange :

это жесткий файл cookie. В C ++ OutOfRange – это общее исключение, расширяющее LogicException (как и в PHP). Я не уверен, что приведенный пример легко переводится на PHP-код, хотя или мое определение времени компиляции выше. В основном потому, что никто не будет сначала инициировать new Vector(10) и сразу же попытаться получить к нему доступ at(20) .

В Java OutOfRange видимому, ссылается на Range в математическом смысле

Диапазон функции – это возможные значения y функции, которые возникают при подстановке всех возможных значений x в функцию.

Одна ссылка, которую я мог найти, это расширение RuntimeException, хотя, поэтому я думаю, что изучение других языков не поможет решить эту тайну. Существует также отчет об ошибке об исключениях SPL в целом , в котором говорится, что

  • OutOfRangeException (значение вне диапазона) – это логическое исключение, должно быть: RuntimeException

Но если это правильно, то как OutOfRange отличается от DomainException? И если ваше собственное определение правильное, то как OutOfRange отличается от InvalidArgumentException ?

Короче говоря: я не знаю, для чего должно быть предназначено OutOfRangeException .

Ответ на ваш вопрос мне тоже довольно неуловим. Однако, вот некоторые вещи, о которых нужно подумать:

  • Если массив передается, когда мы ожидаем действительный ключ массива, у нас также есть InvalidArgumentException потому что это не правильный тип аргумента.
  • Мы также могли бы сбрасывать DomainException потому что массивы не находятся в домене для ключей массива.
  • В php вы обычно не можете обнаруживать типы во время компиляции из-за позднего статического привязки. Они целенаправленно задерживают привязку переменных к времени выполнения.

Как я справляюсь с такой ситуацией:

  • InvalidArgumentException если переменная передается в любую функцию, где аргумент не является правильным. Я все еще делаю это при работе с массивами.
  • Выбросьте InvalidArgumentException если null был принят, когда этого не должно быть. Этого действительно может быть много, потому что null не набирается. Чтобы проверка кода ошибки была простой, я просто придерживаюсь недопустимого аргумента.
  • Throw OutOfBoundsException когда индекс не находится в правильном диапазоне, как вы и предполагали.
  • BadFunctionCallException если пользовательская функция в качестве параметра не имеет правильной формы. Если ваша структура внутри представляет собой массив, имеет смысл, что они могут передавать функцию, чтобы изменить ее, поэтому это иногда возникает.

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

Это довольно просто:

OutOfRange означает «Ваш запрошенный ключ не входит в индекс набора, определенного в коде ».

OutOfBounds означает «Ваш запрошенный ключ не находится в индексе набора, определенного загруженной конфигурацией ».

Путаница в этом случае связана с несколькими факторами. Во-первых, PHP фактически скомпилирован в байт-код. Существует несколько условий исполнения, в которых эта скомпилированная форма сохраняется в относительно постоянной форме на сервере. Однако проблема OutOfRangeException / OutOfBoundsException не об этом, речь идет о ошибке категоризации, сделанной людьми, которые задокументировали эти конкретные классы исключений.

Поскольку PHP динамически типизирован, часто невозможно проверить диапазоны и даже типы во время компиляции. В руководстве указано, что OutOfRangeException следует поднимать во время компиляции, а OutOfBoundsException должно применяться во время выполнения, что является ошибочным различием в этом контексте.

В обоих ручных вводах используется нечеткий язык того, что означает незаконный индекс, но просмотр использования их родительских классов дает некоторые подсказки: LogicExceptions расширяются такими классами, как DomainException, InvalidArgumentException и LengthException, тогда как исключения Runtime – это такие вещи, как UnexpectedValueException, OverflowException и UnderflowException. Из этого шаблона можно сделать вывод, что OutOfRangeException, вероятно, следует применять к нелегальным типам ключей, а OutOfBoundsException следует применять к значениям индекса, которые имеют правильный тип, но не находятся в пределах их контейнера.

Было некоторое обсуждение в списке разработчиков PHP о том, что эти категоризации ошибочны, но проблема идет глубже, чем это. На практике оба исключения могут только быть подняты во время выполнения. Вы можете использовать капризы документации, чтобы выжать различие между недопустимыми типами ключей и недопустимыми значениями индекса, но в этот момент мы говорим об ошибке в документации PHP.

  1. Если вы получите неожиданный индекс. т.е. вы ожидаете string но в конечном итоге с integer или наоборот. Затем вы должны выбросить исключение UnexpectedValueException .
  2. Если вы получаете нужный тип индекса, но его не существует. Затем поднимите warning (trigger_error) и продолжайте. Ожидается, что это не остановит поток программирования.
  3. Если у вас есть объект, который является итерируемым или должен быть итерирован по диапазону, и он достигает своего предела (т. OutOfBoundsException файла), тогда вы должны выбросить OutOfBoundsException .
  4. Все остальное является кандидатом на OutOfRangeException .

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

OutOfRangeException – это нечто серьезное. Кто-то должен посмотреть исходный код. Кто-то должен выяснить, что произошло. Это важно. Теоретически этого никогда не должно было случиться. Вызовите 911. Это ошибка времени компиляции. Сделано фиктивным программистом.

Исключения за пределами диапазона написаны программистами для защиты от ошибок других программистов. Или, может быть, в будущем. Если вы чувствуете, что чего-то подобного никогда не произойдет, используйте Out Of Range. Используйте «Вне пределов» для чего-то, что может случиться.