33

PHP为无效键定义了两个SPL例外:

OutOfRangeException: 请求非法索引时抛出异常。这表示应在编译时检测到的错误。

OutOfBoundsException:如果值不是有效的键,则抛出异常。这表示在编译时无法检测到的错误。

由于 PHP 不是一种编译语言,编译时和运行时之间的区别似乎很奇怪,因此我发现很难理解何时使用哪个异常。

目前我的理解是应该抛出...
...OutOfRangeException如果键从根本上和固有地格式错误,例如,如果数组作为键传递。
...OutOfBoundsException如果密钥通常没问题,但不在某些边界内,例如如果100通过但是50最大密钥。

这种理解正确吗?

4

6 回答 6

27

虽然 PHP 没有经典的“编译时间”(或者没有为此进行大量静态检查的编译器),但我会将“编译时间”视为“我在编写代码时做错的相当静态的东西”和“运行时间”作为“我的逻辑、输入或验证在某些时候关闭”。

所以我的建议是这样对待它:

"Compile Time" / "OutOfRangeException":错误总是可以在源代码中修复,无需或几乎没有逻辑。

我总是取 1-10 的数字,你输入 11


"Run Time" / "OutOfBoundsException": 错误是由于在运行时错误使用造成的。

你创造了我并告诉我取值从 1 到 5 然后你输入 7。不计算

或者

您请求的索引不存在,因为您没有按应有的方式将其放在那里


样本:

我希望 SplFixedArray 抛出一个,OutOfBoundsException因为它的大小是动态的,并且可能在运行时有机会,而我希望Calender::getMonthName抛出类似 a 的东西,OutOfRangeException因为月数肯定是固定在“编译/写入”时间。

数组对象示例:

假设 $array 是一个实现 ArrayAccess 的对象,您可以OutOfBoundsException在这些情况下抛出一个:

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

因为这些值是您对 ArrayAccess 的期望值,但在 SplFixedArray(5) 的情况下它没有意义。替代方案将是DomainException或可能RangeException

OutOfRangeException这些情况下:

$calendar->getMonth(15);

当放置一个数组或一个新类时,代码中肯定存在一些更大的逻辑缺陷,这通常是由程序员一个简单的“哦,我输入了错误的变量”错误造成的。一个(也许更可取的)替代方案是UnexpectedValueExceptionand good old InvalidArgumentException

对于以下情况:

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

一些替代例外似乎更合适。

与 Java 世界比较何时使用的异常并不总是适用的,因为 Java 开发人员有一个附加问题需要处理。

已检查/未检查的异常。许多人认为所有不是运行时异常的东西在 Java 中的用途都非常有限/不应该在内部大量使用)这些名称已经失去了一些原来的含义和意图。

于 2011-11-22T15:10:03.693 回答
11

我自己对此的看法是:

LogicException

用于开发人员犯的任何错误,例如编程/组装应用程序时的错误。当开发人员运行他/她的单元测试时(这将相当于编译时间),这些将有望被捕获。这些异常绝不应该发生在生产现场,因为它们本身就是软件中的错误。

RuntimeException

用于用户犯的任何错误或由于在运行时放入应用程序中的无效数据而导致的任何错误。这些是单元测试可能可以预见但不能完全预防的错误,例如,这些错误可能发生在生产站点上。这些异常可能源于不正确的使用或编程错误。

OutOfBounds

IMO 实际上是 Wikipedia 定义为计算机编程范围内数组的范围,即:

当一个数组被数字索引时,它的范围是数组的上限和下限。根据环境的不同,如果程序尝试访问超出范围的数组元素,则会出现警告、致命错误或不可预知的行为。

换句话说,当您有一个索引为 [0,1,2] 的数组时,除了 [0,1,2] 之外的任何内容都超出了范围。请注意,Bounds 也可以应用于其他数据类型,例如,尝试访问 5 个字符的字符串中的第 7 个字符也将是 OutOfBounds。

OutOfRange

这是一块坚硬的饼干。在 C++中,OutOfRange是一个扩展 LogicException 的通用异常(就像在 PHP 中一样)。我不确定给出的示例是否可以轻松转换为 PHP 代码,或者我对上面编译时间的定义。主要是因为没有人会先初始化一个new Vector(10)并立即尝试访问它at(20)

在 JavaOutOfRange中似乎指的是数学意义上的 Range

函数的范围是当我们将所有可能的 x 值代入函数时,函数可能的 y 值。

我可以找到一个参考,它扩展了 RuntimeException,所以我想研究其他语言无助于解决这个谜团。还有一个关于 SPL 异常的公开错误报告,指出

  • OutOfRangeException(值超出范围)是LogicException,应该是:RuntimeException

但如果这是正确的,那么 OutOfRange 与 DomainException 有何不同?如果您自己的定义是正确的,那么 OutOfRange 与 有何不同InvalidArgumentException

长话短说:我不知道OutOfRangeException应该做什么。

于 2011-11-22T16:46:57.850 回答
4

你的问题的答案对我来说也很难以捉摸。但是,这里有一些事情需要考虑:

  • 如果当我们期望一个有效的数组键时传入一个数组,我们也有,InvalidArgumentException因为它不是正确的参数类型。
  • 我们也可以抛出 aDomainException因为数组不在数组键的域中。
  • 在 php 中,由于后期静态绑定,您通常无法在编译时检测类型。他们故意将变量绑定到运行时。

我如何处理这种情况:

  • InvalidArgumentException如果将变量传递给参数不是正确类型的任何函数,则抛出一个。使用数组时我仍然这样做。
  • 在不应该的时候抛出一个InvalidArgumentExceptionif被传入。null这真的可能是很多事情,因为 null 没有被输入。为了保持错误代码检查简单,我只是坚持使用无效参数。
  • OutOfBoundsException正如您建议的那样,当索引不在正确范围内时抛出。
  • BadFunctionCallException如果作为参数的用户提供的函数没有正确的形式,则抛出。如果你的内部结构是一个数组,那么他们可以传入一个函数来修改它是有道理的,所以偶尔会出现这种情况。

一般来说,我可以只使用这三个异常来表示在特殊资源之外发生的所有错误(网络和数据库连接将是特殊资源)。第三个似乎更频繁地出现,但主要是我刚刚处理了前两个。

于 2011-11-19T17:34:12.700 回答
4

这很简单:

OutOfRange 的意思是“您请求的密钥不在code 中定义的集合的索引内。”

OutOfBounds表示“您请求的密钥不在加载的配置定义的集合的索引内。”

于 2013-12-09T22:47:08.770 回答
2

这种情况下的混乱来自几个因素。首先,PHP 实际上被编译成字节码。有几个执行环境,这个编译的形式在服务器上以相对永久的形式存在。但是,OutOfRangeException/OutOfBoundsException 问题与此无关,它与记录这些特定异常类的人所犯的分类错误有关。

由于 PHP 是动态类型的,因此通常不可能在编译时实际检查范围甚至类型。该手册指出 OutOfRangeException 应在编译时引发,OutOfBoundsException 应在运行时应用,这是在此上下文中做出的错误区分。

两个手动条目都使用不清楚的语言来说明非法索引的含义,但查看其父类的用法会给出一些线索:LogicExceptions 由 DomainException、InvalidArgumentException 和 LengthException 等类扩展,而运行时异常是 UnexpectedValueException、OverflowException 和下溢异常。从这种模式可以推断出 OutOfRangeException 可能应该应用于非法键类型,而 OutOfBoundsException 应该应用于类型正确但不在其容器范围内的索引值。

PHP 开发人员列表上有一些关于这些分类错误的讨论,但问题远不止于此。实际上,这两个异常实际上只能在运行时引发。您可以使用文档的变幻莫测来区分无效键类型和无效索引值,但此时我们讨论的是 PHP 文档中的错误。

于 2011-11-28T23:18:04.030 回答
-1
  1. 如果你得到一个意外的索引。即,您期望 astring但最终以a 结束,integer反之亦然。那么你应该抛出一个UnexpectedValueException异常。
  2. 如果您获得正确类型的索引但它不存在。然后提出 a并继续。预计这不会停止编程流程。warning (trigger_error)
  3. 如果您有一个可迭代的对象或应该在一个范围内迭代并且它达到它的限制(即文件的结尾),那么您应该抛出一个OutOfBoundsException.
  4. 其他任何东西都是OutOfRangeException.

通俗地说。安OutOfBoundsException是正常的。没那么严重。这是经常发生的事情,应该加以注意。迭代器可以使用它来继续读取数据,直到没有更多要读取的数据为止。这是一个逻辑错误。由使用代码的人而不是由编写代码的人制作。

一个OutOfRangeException是严肃的。有人应该看看源代码。应该有人知道发生了什么。这个很重要。从理论上讲,这是不应该发生的。拨打 911。这是编译时错误。由虚拟程序员制作。

超出范围的异常由程序员编写,以防止其他程序员出错。或者,也许未来的你自己。如果您觉得这样的事情永远不会发生,请使用超出范围。使用 Out of Bounds 表示可能发生的事情。

于 2014-01-31T20:22:13.870 回答