控制器可以捕获模型抛出的异常吗?

时间:2013-01-08 22:12:21

标签: php model-view-controller exception model controller

嗯,这在技术上是可行的,但这会破坏MVC架构吗?

我不确定控制器和型号之间是否建议进行此类通信。我将使用一个简单的示例和两种方法来描述它:

选项1(模型抛出异常,控制器捕获它):

class Controller {
  private $model;

  public function save($data) {
     try {
         $this->model->save($data); 
     } catch (Exception $e) {  
         // handle exception
     }
  }
}

class Model {
  public function save($data) {
     // Call to internal function to save data in BD
     if (! $this->_save($data)) throw new Exception('Error saving data');
  }
}

选项2(控制器完全处理异常):

class Controller {
  private $model;

  public function save($data) {
     try {
         if (! $this->model->save($data)) throw new Exception('Error saving data'); 
     } catch (Exception $e) { 
         // handle exception
     }
  }
}

class Model {
  public function save($data) {
     // Call to internal function to save data in BD
     if (! $this->_save($data)) return false;
  }
}

**

在一些回复之后编辑:

**

这些是根据您的建议解决问题的其他方法。我希望不要太复杂。

选项3(模型完全处理异常,正如Ray所说.KingCrunch还建议在模型中做得更好)

class Controller {
  private $model;

  public function save($data) {

     if (! $this->model->save($data)) {
         // possible action: redirect to the form with an error message
     }

  }
}

class Model {
  public function save($data) {
     try {
         if (! $this->_save($data)) throw new Exception('Error saving data'); 
     } catch (Exception $e) { 
         // handle exception
         return false;
     }
     return true; 
  }
}

选项4(控制器获取模型抛出的自定义子例外,如shiplu.mokadd.im所说。)

class Controller {
  private $model;

  public function save($data) {
     try {
         $this->model->save($data); 
     } catch (Exception $e) {  
         if ($e instanceof ValidationException) {
            // handle validation error
         }
         elseif ($e instanceof DBStorageException) {
            // handle DB error
         }
     }
  }
}

class Model {
  public function save($data) {
     if (! $this->_validate($data)) {
        throw new ValidationException ('Validation error');
     }
     if (! $this->_save($data)) {
        throw new DBStorageException ('Storage error');
     }
  }
}

3 个答案:

答案 0 :(得分:6)

模型可以抛出异常,控制器或视图应该捕获它。否则你永远不知道一切都在那里正常工作。所以使用第一个选项。但是确保你正在抛出对控制器和View 有意义的正确抽象异常。

为了说明上面的粗线,请参阅模型中使用的这两个throw语句。

 throw new Exception('SQL Error: '.$mysqli->error()); // dont use it
 throw new DuplicateFieldException('Duplicate username'); // use this

第二个示例未显示内部错误。相反,它隐藏了它。控制者永远不应该知道内部发生了什么。

在您的代码中,您将单个模型绑定到单个控制器。控制器不代表单个模型。它使用模型。它可以使用任意数量的模型。因此,不要将单个模型与具有private $model变量的控制器联系起来。

答案 1 :(得分:2)

绝对是第一选择。有些话:

  • 这是控制器的工作......好吧,控制。这意味着,应该注意,至少会出现一个有用的错误消息。应用程序的其他部分可以在它们能够处理特殊情况之前执行。这包括模型本身:如果它能够处理它,它应该这样做。

  • save()表示“保存”。不要滥用状态信息的返回值。如果方法不能save()它是一个例外,并且当一个方法不必给你一些东西时,它就不应该给你一些东西。

答案 2 :(得分:1)

我更喜欢选项3.

模型应该捕获异常,尝试解决它,如果没有将其渗透到控制器,但只有控制器可以解决并从中恢复。在这种情况下,(某种类型的DB保存失败)在返回false的模型中捕获它应该足以解决保存错误并为控制器提供足够的信息以便在保存时知道出错。

控制器不需要担心模型如何实现保存的实现细节。