【问题标题】:Nesting ifs to catch errors [duplicate]嵌套ifs以捕获错误[重复]
【发布时间】:2014-07-08 20:42:36
【问题描述】:

你可能知道这张图片:

假设我想验证单个用户输入通过各种方法,每个方法都取决于前一个方法的成功。如果嵌套,我怎样才能避免这种麻烦和丑陋?

我想不出其他方法,它可以正确验证并在发生错误时返回正确的消息,但它看起来确实很丑,而且维护起来可能很麻烦。

有什么想法吗?

【问题讨论】:

  • 您应该默认简化验证。很可能您不需要超过 2 次检查即可完全确定用户失败。和超过 2 个其他的,以确保它没问题。
  • 每次出错后直接返回即可,无需继续

标签: php if-statement


【解决方案1】:

到目前为止,我的经验表明,如果您对同一目标进行了 4-5 次以上的验证,那么您很可能做错了什么。为了验证用户输入,您可能需要某些字符模式,您可以使用正则表达式来实现,您可能需要填充所有字段,一些奇特的东西,例如用户来自某个国家/地区 IP 或检查至少 18 岁在下拉列表中。所有其他的东西,要么属于这组,要么可能是——它们是多余的。

正如其他人所说,您也不应该嵌套块,如果不满足条件,则返回执行。

例如:

function isFormPopulated() {
    $requiredFields = array('user', 'pass', 'age', 'sex');
    foreach ($requiredFields as $field) {
        if (empty($_POST[$field])) { 
            $_SESSION['msg'] = $field . ' field should be populated'; // here better throw exception, instead of session saving the message
            return false;
        }
    }
    return true;
}

function isPatternValid() {
     $fieldPatterns = array('user' => '/w+/', 'pass' => 'someOtherRegex')
     foreach ($fieldPatterns as $field => $pattern) {
         if (!preg_match($pattern, $_POST[$field])) {
             return false;
         }
     }
     return true;
}

function isUserAllowed() {
    if (in_array($_SERVER['REMOTE_ADDR']......) {
        return false;
    }
    return true;
}

function isUserLegal() {
    if ($_POST['age'] < self::MIN_ALLOWED_AGE) {
        return false;
    }
    return true;
}

function isValid() {
     // here you can check with && the evaluation of the previous functions
     // or you can check one by one and return false aswell
     // return true at the end
}


function register() {
     if (!isValid()) {
         return false;
     }
     // continue execution of the registration process
}

在大多数情况下,验证用户输入与每个条件无关。例如。正则表达式条件不与法律条件耦合。但是,如果按设计(我认为这是错误的)你有耦合。你可以链式验证像

function validationFour() {
    if (!validationThree() || !current_validation) {
        return false;
    }
    return true;
}

function validationThree() {
    if (!validationTwo() || !current_validation) {
        return false;
    }
    return true;
}

【讨论】:

    【解决方案2】:

    一个好的做法是防止深度嵌套的语句。所以最好找到负面情况,并立即处理。例如:

    if(!$_POST['user_name']){
        // exit
    }
    
    if(!$_POST['password']){
        // exit
    }
    
    // if we get to here, we assume all previous checks passed
    

    这会创建干净的代码,因为深度嵌套的代码更难维护,并且在找到条件后立即处理。

    【讨论】:

      【解决方案3】:

      您可以使用 try/catch 块并在验证失败时抛出异常。例如:

      try {
        if (!$_POST['user_name']) {
          throw new Exception('Invalid username');
        }
      
        if (!$_POST['user_password_new']) {
          throw new Exception('Invalid password');
        }
      
      } catch (Exception $e) {
        echo 'Caught exception: ',  $e->getMessage(), "\n";
      }
      

      【讨论】:

      • 所以最后你有20个if,和图片一样?
      • @RoyalBg 是的,但它们没有嵌套。
      • 如果条件是检查 N 个字段是否为空,为什么不保留一个包含字段名称和相应消息的映射,并在循环中检查其中一个键是否为空,以返回它的映射消息?
      • @RoyalBg 再次阅读问题。 OP 说:“通过各种方法验证单个用户输入”。在这种情况下,foreach 将无济于事。这段代码只是一个例子,让 OP 知道如何去做。
      • 那么,为什么不每个方法检查前一个的成功,例如一个validPassword() 方法检查emptyFields() &amp;&amp; strlen(...) &gt; NemptyFields() 检查someOtherDependantCondition() &amp;&amp; empty(...),然后在register() 中只调用了一个isValid() 方法,它调用了链中的最后一个?
      【解决方案4】:
      if (!$_POST['user_name']) {
          $_SESSION['msg'] = 'Empty Username';
          return register_form();
      }
      
      if (!$_POST['user_password_new']) {
          $_SESSION['msg'] = 'Empty Password';
          return register_form();
      }
      
      ...
      
      create_user();
      ...
      

      【讨论】:

      • 我会使用带键的数组 -> 发布字段、值 -> 必要的消息,然后遍历数组,如果 $_POST[$key] 为空 -> $_SESSION['msg'] = $价值。而不是 if 用于每个字段并返回。
      【解决方案5】:

      根据下面的说法,看来你可以把它们堆叠起来,如果前一个失败就立即返回。如果上一个成功,那么执行下一个检查是安全的。

      每一个都取决于前一个的成功

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-10
        • 2018-08-02
        • 1970-01-01
        • 2019-07-22
        • 2017-04-12
        • 2021-12-12
        相关资源
        最近更新 更多