【问题标题】:Exceptions - what is "exceptional"?例外——什么是“例外”?
【发布时间】:2016-11-23 17:01:52
【问题描述】:

我了解到,异常不应用于指导应用程序的流程,而应用于在发生“异常”时(例如,当您无法连接到数据库。

不应使用异常的一个示例是用户提供了不正确的登录名。这不会是一个例外,因为预计会发生这种情况。

我不确定以下情况是否例外:

我目前正在设计一个简单的博客。一个“帖子”只分配给一个“类别”。在我的帖子表中,我有一个带有外键约束的 category_id 字段。

现在,我正在使用 Laravel,因此如果我尝试删除当前包含帖子的类别,我相信由于外键约束,它应该抛出 \Illuminate\Database\QueryException。因此我应该依赖这个并编写如下代码:

try {
    $category->delete();
}
catch (\Illuminate\Database\QueryException $e) {
    // Tell the user that they can't delete the category because there are posts assigned to it
}

或者既然我知道我希望我的博客如何工作,我应该使用:

if ($category->posts->isEmpty()) {
    $category->delete();
}
else {
    // Tell the user they can't delete...
}

任何建议将不胜感激。谢谢!

【问题讨论】:

  • 我认为这主要是基于意见的,但我会选择第二种选择。为什么? 1. 使规则清晰。 2. 使其他类型的数据库异常不会产生误导性错误。 3. 这样如果有人开启级联删除,你的逻辑还是一样的。
  • 继续@DarkFalcon 的回答,抛出异常是一项繁重的操作,所以你应该只在你真的没有发生的情况下使用它。

标签: php laravel exception


【解决方案1】:

这是非常基于意见的,所以我会给你我的意见: 异常非常强大,因为您可以在其中附加大量信息 - 您可以将它们发送到“调用堆栈”,而无需数百个方法检查任何调用的返回值并将任何内容返回给它们自己的调用者。

这使您可以轻松地处理调用堆栈中所需层的错误。

方法应该返回,调用的结果是什么(即使它是无效的)。如果调用因任何原因失败,应该有没有返回值。

错误不应该通过返回值来传递,而是有异常。

想象一个执行 db 查询的函数:KeyAlreadyExistsExceptionInvalidSyntaxExceptionNullPointerException - 您很可能希望在代码中非常不同的部分处理这些“错误”。

(一个是代码错误,一个是查询错误,一个是逻辑错误)

示例一,轻松“处理”:

try{
  method1(1);
}catch (Exception $e){
  //Handle all but NullpointerExceptions here.
}
---
method1($s){
  try{
    method2($s+2);
  } catch (NullPointerException $e){
    //only deal with NPEs here, others bubble up the call stack.
  }
} 
---
method2($s){
  //Some Exception here.
}

示例二 - 你看到了所需的“嵌套”,这里的堆栈深度只有 2。

 $result = method1(1);
 if ($result === 1){
   //all good
 }else{
  //Handle all but NullpointerExceptions here.
 }
 ---
 method1($s){
   $result = method2($s+2);
   if ($result === 1){
     return $result;
   }else{
     if ($result === "NullPointerException"){
       //do something
     }  
 } 

method2($s){
  //Exception here.
}

特别是在维护方面,异常有很大的优势:如果你添加一个新的“异常”——最坏的情况是一个未处理的异常,但代码执行会中断。

如果您添加新的“返回错误”,您需要确保每个调用者都知道这些新错误:

function getUsername($id){
   // -1 = id not found
   $name = doQuery(...);
   if (id not found) return -1;
   else return $name;
}

function getUsername($id){
   $name = doQuery(...);
   if (id not found) throw new IdNotFoundException(...);
   return $name;
}

现在考虑两种情况的处理:

if (getUsername(4)=== -1) { //error } else { //use it }

try{
  $name = getUsername(4);
  //use it
}catch (IdNotFoundException $e){
   //error
}

现在,您添加返回代码-2:第一种方式将假定用户名是-2,直到错误代码被实现。第二种方式(另一个异常)将导致执行停止,并在调用堆栈中某处出现未处理的异常。

处理错误传输的返回值(任何类型)很容易出错,错误可能会消失在某个地方,变成“错误”的解释结果。

使用异常更安全:您要么有要使用的返回值,要么有(已处理或未处理的)异常,但不会因自动转换等而出现“错误值”。

【讨论】:

    猜你喜欢
    • 2014-06-28
    • 2016-02-19
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-08
    • 1970-01-01
    相关资源
    最近更新 更多