假设有一个模型在保存对象上执行某些逻辑。该逻辑由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世界中的错误(事务性和其他)的最佳实践?我提供的哪种解决方案是最好的解决方案?
答案 0 :(得分:0)
使用ORM(如Doctrine)并让Unit Of Work负责处理事务。
所有INSERT
/ UPDATE
/ DELETE
操作都会排队,直到您调用YOUR_ORM::flush
为止。发生异常时,事务会自动回滚。