0

我正在尝试将多个 setter 方法链接在一起。我想知道是否有人知道解析多个错误的干净方法,最好使用 try-catch 块使用默认的 Exception 类进行处理。

按照现在的代码,我收到的只是第一个被捕获的异常对象(来自 foo),所以我只能向用户显示一个错误。

任何指针或约定将不胜感激!

class Test {
   function setName($name) {
      if (empty($name))
         throw new Exception("Name is empty.");

      return $this;
   }

   function setDescription($description) {
      if (empty($description))
         throw new Exception("Description.");

      return $this;
}


try {

   $object->setName("foo")
          ->setDescription("bar");

} catch(Exception $e) {

}
4

5 回答 5

5

您可以捕获不同的异常,但一次只能捕获 1 个。异常不仅仅是警告通知,异常意味着函数无法获得预期的结果,程序不能简单地继续。不能用来告诉用户他没有填写特定字段。

为此使用其他技术。

于 2013-10-02T07:18:49.443 回答
1

根据它的定义,您不能抛出多个异常(类似于为什么不能多次从函数返回结果)。

在您的情况下 - 您可以存储一些带有结果的结构,您将在类中写入操作错误。然后,如果它不为空,则使用收集的内容引发异常。

于 2013-10-02T07:19:34.510 回答
0

您可能需要研究错误处理和异常:异常是针对异常情况的,这些情况看起来像您经常遇到的情况:如果出现意外情况,您会抛出异常并停止您正在做的任何事情。由于状态未知,您无法继续做更多的工作,因为您处于这种特殊情况。

如果您想在发生错误的情况下引导流程,您应该编写某种不基于异常的错误处理程序,以便您继续工作,但将错误报告给用户。

有很多要阅读的内容,您想查找有关使用“异常作为流控制”的资源,以及为什么这是一个坏主意。

于 2013-10-02T07:24:53.350 回答
0

an 的要点Exception是发生了一些你无法恢复的事情。因此,它会停止执行并冒泡,直到它位于顶部 ( Error: Uncaught Exception) 或直到它被 a 捕获并处理try/catch

如果您绝对想要多个错误,您可以在类中跟踪该状态:

abstract class Statefull // abstract because it makes no sense instantiating this
{
    protected $isValid = true;
    protected $errors = array();

    protected function invalidate($field, $error) {
        $this->isValid = false;
        $this->errors[$field] = $error;
    }

    public function isValid() { return $this->isValid; }

    public function getErrors() { return $this->errors; }
}

这个示例类允许每个字段出现一个错误,并且可以按如下方式进行扩展。

class Test extends Statefull
{
    protected $name;
    protected $description;

    function setName($name) {
        if (empty($name)) this->invalidate('name', 'Name is empty');
        else $this->name = $name;

        return $this;
    }

    function setDescription($description) {
        if (empty($description)) this->invalidate('description', 'Description is empty');
        else $this->description = $description;

        return $this;
    }
}

并且可以这样使用:

$test = new Test();
$test->setName('')->setDescription('');
if (!$test->isValid()) {
    var_dump($test->getErrors());
    die();
}

如果你有 PHP 5.4,你也可以通过以下方式解决这个问题traits

trait Statefull
{
    protected $isValid = true;
    protected $errors = array();

    protected function invalidate($field, $error) {
        $this->isValid = false;
        $this->errors[$field] = $error;
    }

    public function isValid() { return $this->isValid; }

    public function getErrors() { return $this->errors; }
}

然后实现将是这样的,其优点是不需要扩展类(如果您已经从不同的基类扩展您的模型):

class Test
{
    use Statefull;
    protected $name;
    protected $description;

    function setName($name) {
        if (empty($name)) this->invalidate('name', 'Name is empty');
        else $this->name = $name;

        return $this;
    }

    function setDescription($description) {
        if (empty($description)) this->invalidate('description', 'Description is empty');
        else $this->description = $description;

        return $this;
    }
}

用法和以前一样。如果您这样做,请注意特征中的限制属性带来的限制:

如果一个 trait 定义了一个属性,那么一个类不能定义一个同名的属性,否则会发出错误。如果类定义兼容(相同的可见性和初始值),则为 E_STRICT,否则为致命错误。

于 2013-10-02T07:26:54.143 回答
0

当抛出异常时,代码停止并且异常将冒泡,直到 catch 指令处理它。

所以当你这样做时:

   $object->setName("foo")
          ->setDescription("bar");

如果 setName 的调用引发异常,则不会调用您的第二个 setter。

在您的情况下,您需要自己处理错误:

class Test {
   private $errors = array();

   function setName($name) {
      if (empty($name))
         $this->errors[] = "Name is empty.";

      return $this;
   }

   function setDescription($description) {
      if (empty($description))
         $this->errors[] = "Description.";

      return $this;
}
于 2013-10-02T07:21:52.350 回答