在方法中抛出无效参数的异常

时间:2014-01-07 16:55:28

标签: php oop exception object methods

我正在学习异常处理。我已经知道如何使用它们了,但我不知道何时使用它们,因为很少有教程告诉你有关这方面的任何见解。我的代码:

// 0-index part of the url
public function part($Part)
  {
  if (!is_numeric($Part))
    throw new Exception('The argument for $Url->part() should be numeric');

  $Part = (int) $Part;

  if ($Part < 0)
    throw new Exception('The argument for $Url->part() should be positive');

  if ($Part > count($this->parts))
    return false;

  return $this->parts[$Part];
  }

我觉得我的代码有太多异常。它是检索当前url及其中某些部分的代码的一部分。例如,/this/is/a/test/$this->parts保存为array('this', 'is', 'a', 'test')

我在该方法中使用了太多异常,阻碍了可读性吗?如果出现任何问题,我是否应该只使用一个例外,使调试稍微困难但更容易阅读源代码?

这是问题中提到的更通用的异常:

// 0-index part of the url
public function part($Part)
  {
  if (!is_numeric($Part) || intval($Part) < 0 || intval($Part) > count($this->parts))
    throw new Exception('The argument for $Url->part() is not correct');

  return $this->parts[(int) $Part];
  }

2 个答案:

答案 0 :(得分:4)

实际上,您的问题与基于意见的问题非常接近(因此,如果没有非建设性的讨论,可能难以正确回答)。但是,有一些事情是有用的记住。

首先,提高只是异常可能会有所改进 - 因为PHP中有标准的exceptions。投掷它们将有效地提高可读性。例如,您的代码接受一些应该是数字的参数。如果不是 - 那么它是无效参数 - 因此,可能会触发相应的异常。接下来,您的parts是一个数组 - 并且您想要检查是否存在传递的偏移量。如果不是,那么它是越界异常。因此,您的代码可能如下所示:

public function getPart($part)
{
   if(!is_numeric($part))
   {
      throw new InvalidArgumentException('Invalid part number passed');
   }
   if(!array_key_exists($part, $this->parts))
   {
      throw new OutOfBoundsException('Offset '.$part.' not found in parts');
   }
   return $this->parts[$part];
}

- 这对于数字偏移似乎是合理的。但是,如果您的结构包含更复杂的数据,那么您可能需要引发逻辑异常(指出传递的参数或当前结构的逻辑结构中存在错误)。

通常情况下 - 所有都取决于情境和逻辑没有银弹 - 它是关于设计的,所有解决方案都是相对的,并且与某些情况有关。

同样,这是基于意见的(例如,我从重新命名方法开始到getPart() - 因为对我而言,方法是一个应该被命名为动作的实体名字,而不仅仅是名字)。而且,更多 - 尝试避免在返回某些内容时混合使用不同的类型(例如样本中的false)。它会导致不可靠的行为。最好抛出异常,但保持你的函数/方法返回类型相同。

答案 1 :(得分:2)

  

@Mark,我想要验证的不是用户输入,而是程序员的输入。

是的,这太过分了。如果您想要检查程序员输入,请用户assert

没有合理的方法来处理由错误代码生成的异常,或者疯狂的参数,或者错误地使用库,这是您似乎要防范的。使用异常作为防范此类错误的机制没有任何价值。

当出现意外情况时会引发异常,而您无法正常处理它。异常将控制权传递回堆栈,理想情况下是一个可以处理错误类型的级别,而不会导致程序失败。在运行时实际上没有办法处理你正在防范的那种错误。如果有人给你的库输入是错误的,你的库只能中止,那么我们能做的最好的事情是给用户尽可能多的调试信息并退出; assert是专为此目的而构建的。

请注意,我认为即使assert通常也会过度杀戮。您使用的是duck-typed语言;谁在乎你的论点类型?只要他们响应您将要调用的所有方法,您的代码就应该乐于接受任何类型的对象。我会考虑在我的参数上使用assert的唯一情况是,当我编写库代码时,我知道我想生成比PHP更友好的错误消息。