如何设计代码而不重复捕获mvc框架中的错误?

时间:2015-10-07 12:09:57

标签: php design-patterns model-view-controller error-handling silex

假设有一个模型在保存对象上执行某些逻辑。该逻辑由db-transactions,一些外部服务调用组成。

class ExampleModel {
  //some field
  //constructor and getters with setters

  public function save() {
    $db->beginTransaction();
    $db->somequery();
    $db->anotherone();
    $object->externalApiCall();
    $object->saveToCache();
  }


}

我的问题是捕获错误和回滚的最佳方法是什么?

溶液#1 捕获模型中的所有内容,在那里回滚,记录一些信息并将错误重新抛出到控制器。会看起来像这样:

class ExampleModel {
  //some field
  //constructor and getters with setters

  public function save() {
    try {
     $db->beginTransaction();
     $db->somequery();
     $db->anotherone();
     $object->externalApiCall();
     $object->saveToCache();
    } catch (DbException $e) {
      $db->rollback();
      $logger->log($e->getMessage());
      throw $e
    }
     catch (ApiExcetpion $e) {
       somelogic();
       throw $e;
     }
  }


}

我对这种方法的主要关注是编写try / catch块时存在很多冗余。对于每个复合方法,都会有try catch块。

解决方案#2 抛出模型中的错误,并在控制器中处理回滚/日志记录等。这个我不喜欢因为它破坏了MVC模式,而控制器变得很胖。

解决方案#3 将错误侦听器绑定到应用程序实例,以便它们根据逻辑处理异常。例如:

class ExampleModel {
  //some field
  //constructor and getters with setters

  public function save() {
    $db->beginTransaction();
    $db->somequery();
    $db->anotherone();
    $object->externalApiCall();
    $object->saveToCache();
  }


}

$app->bind_error_handler("DbTransactionException", function () {
     rollback();
     log();
     return View::render("some error");
});

我总体上喜欢这种方法,因为没有很多try / catch块。控制器是瘦的,错误逻辑与其他一切都是分离的。我对最后一种方法的关注是它是否被认为是最佳实践。这种方法也是灵活的,它会给我第一种方法的灵活性吗?

总体问题: 什么是处理MVC世界中的错误(事务性和其他)的最佳实践?我提供的哪种解决方案是最好的解决方案?

1 个答案:

答案 0 :(得分:0)

使用ORM(如Doctrine)并让Unit Of Work负责处理事务。

所有INSERT / UPDATE / DELETE操作都会排队,直到您调用YOUR_ORM::flush为止。发生异常时,事务会自动回滚。