0

我在 MVC 框架中编写了一些代码,如下所示:

class Controller_Test extends Controller
{
   public function action_index()
   {
      $obj = new MyObject();
      $errors = array();

      try
      {
         $results = $obj->doSomething();
      }
      catch(MyObject_Exception $e)
      {
         $e->getErrors();
      }
      catch(Exception $e)
      {
         $errors[] = $e->getMessage();
      }
}

我的朋友争辩说,Controller 应该对 MyObject 一无所知,因此我不应该捕获 MyObject_Exception。

他认为代码应该做这样的事情:

class Controller_Test extends Controller
{
   public function action_index()
   {
      $obj = new MyObject();
      $errors = array();

      if($obj->doSomething())
      {
         $results = $obj->getResults();
      }
      else
      {
         $errors = $obj->getErrors();
      }
}

我绝对理解他的方法,但感觉好像状态管理会导致意想不到的副作用。

什么是正确或首选的方法?

编辑:错误地将 $obj->getErrors() 放在 MyObject_Exception catch 子句中,而不是 $e->getErrors();

4

3 回答 3

1

总的来说,我会说重要的是控制器是否理解异常的含义并能够正确处理它。在许多情况下(如果不是大多数情况下),控制器将不知道如何正确处理异常,因此不应捕获和处理它。

另一方面,控制器可能被合理地允许理解一些特定的异常,例如“DatabaseUnavailableException”,即使它不知道如何或为什么MyObject使用数据库。控制器可能被允许重试调用MyObject一定次数,所有这些都不知道是如何MyObject实现的。

于 2013-02-12T05:16:02.287 回答
1

关于异常与返回的错误代码的争论是一场漫长而血腥的争论。

他的论点分解为,通过使用 getErrors() 函数,您正在了解有关 object 的信息。如果这是您使用布尔返回来表示成功的原因,那么您就错了。为了让控制器正确处理错误,它必须知道它正在触摸的对象以及具体的错误是什么。是网络错误吗?内存错误?它必须以某种方式知道。

我更喜欢异常模型,因为它更简洁,允许我以更可控的方式处理更多错误。它还为与异常相关的数据提供了一种明确的传递方式。

但是,我不同意您使用 getErrors() 之类的函数。任何与异常有关的有助于我处理它的数据都应该包含在异常中。我不应该再去寻找对象来获取关于哪里出了问题的信息。

网络连接超时了吗?异常应包含它尝试连接的主机/端口、等待的时间以及来自较低网络级别的任何数据。

让我们在示例中执行此操作(在伪 c# 中):

public class NetworkController {
    Socket MySocket = null;
    public void EstablishConnection() {
        try {
            this.MySocket = new Socket("1.1.1.1",90);
            this.MySocket.Open();

        } catch(SocketTimeoutException ex) {
            //Attempt a Single Reconnect
        }
        catch(InvalidHostNameException ex) {
            Log("InvalidHostname");
            Exit();
        }

    }
}

使用他的方法:

public class NetworkController {
    Socket MySocket = null;
    public Boolean EstablishConnection() {
        this.MySocket = new Socket("1.1.1.1",90);
        if(this.MySocket.Open()) {
            return true;
        } else {
            switch(this.MySocket.getError()) {
                case "timeout":
                    // Reattempt
                    break;
                case "badhost":
                    Log("InvalidHostname");
                    break;
            }
        }
    }
}

最终,您需要知道对象发生了什么才能知道如何响应它,并且使用一些复杂的 if 语句集或 switch-case 来确定它是没有意义的。使用例外并爱他们。

编辑:我不小心说了后半句。

于 2013-02-12T05:17:55.407 回答
1

首先,控制器并不意味着处理类抛出的底层异常。

即使发生这种情况,控制器也应该停止在潜在错误中说错话。

通过这种方式,我们可以确保控制器确实并且只做流量控制的工作。

给控制器一些输出的其他类应该没有错误,除非错误是非常特定于控制器的。

于 2013-02-12T08:03:47.657 回答