【问题标题】:Alternative for too many switch case for cyclomatic complexity reduction?减少圈复杂度的太多开关盒的替代方案?
【发布时间】:2018-08-31 08:32:34
【问题描述】:

我有一个检查 $value 类型是否有效的功能。我当前的代码是一个简单的 switch 案例,其中太多的案例超过了圈复杂度到 17。我需要添加更多案例并降低复杂度。

 /**
 * Check type of attribute value
 * @param $type
 * @param $value
 * @return bool
 */
public function typeCheck($type, $value)
{
    $this->value = $value;
    switch ($type) {
        case 'string':
            return is_string($value) || is_integer($value) || is_bool($value);
        case 'StringNotNull':
            return is_string($value);
        case 'LongStringNotNull':
            return is_string($value);
        case 'SuperLongStringNotNull':
            return is_string($value);
        case 'FortyStringNotNull':
            return is_string($value) && (strlen($value) < 41);
        case 'integer':
            return is_numeric($value);
        case 'positiveInteger':
            return is_numeric($value) && ($value > 0);
        case 'boolean':
            return is_bool($value) || ($value == 'true' || $value = 'false');
        case 'float':
            return is_numeric($value);
        case 'decimal':
            return is_numeric($value);
        case 'PositiveDimension':
            return is_numeric($value) && ($value > 0);
        case 'Dimension':
            return is_numeric($value) && (strlen($value) < 13);
        case 'Barcode':
            $validator = $this->getBarcodeValidator();
            $validator->setBarcode($value);
            return is_string($value) && (strlen($value) < 17 && $validator->isValid());
        case 'dateTime':
            return true;
        case 'normalizedString':
            $this->value = strip_tags($value);
            return is_string($value);
        default:
            return is_string($value);
    }
}

有更好的方法吗?

【问题讨论】:

    标签: php if-statement switch-statement cyclomatic-complexity


    【解决方案1】:

    您可以用数据结构替换开关:

    public function typeCheck($type, $value) {
    
        $typeTestMap = [
            'string' => function($value) { return is_string($value) || is_integer($value) || is_bool($value); },
            'FortyStringNotNull' => function($value) { return is_string($value) && (strlen($value) < 41); },
            ...
        ];
    
        if (isset($typeTestMap[$type])) {
            return $typeTestMap[$type]($value);
        } else {
            return is_string($value);
        }
    }
    

    【讨论】:

    • 非常感谢。我不知道 PHP 支持匿名函数。还有,我的 PhpStorm 在写代码的时候还是会报语法错误,你是不是已经遇到过这个问题了?
    • 不能使用数组作为静态变量的初始值。我已将其重新编码为仅使用普通的局部变量。
    【解决方案2】:

    好吧,你可以将具有相同功能的那些分组:

    public function typeCheck($type, $value)
    {
        $this->value = $value;
        switch ($type) {
            case 'string':
                return is_string($value) || is_integer($value) || is_bool($value);
            case 'FortyStringNotNull':
                return is_string($value) && (strlen($value) < 41);
            case 'positiveInteger':
                return is_numeric($value) && ($value > 0);
            case 'boolean':
                return is_bool($value) || ($value == 'true' || $value = 'false');
            case 'float':
            case 'decimal':
            case 'integer':
                return is_numeric($value);
            case 'PositiveDimension':
                return is_numeric($value) && ($value > 0);
            case 'Dimension':
                return is_numeric($value) && (strlen($value) < 13);
            case 'Barcode':
                $validator = $this->getBarcodeValidator();
                $validator->setBarcode($value);
                return is_string($value) && (strlen($value) < 17 && $validator->isValid());
            case 'dateTime':
                return true;
            case 'normalizedString':
                $this->value = strip_tags($value);
                return is_string($value);
            case 'StringNotNull':
            case 'LongStringNotNull':
            case 'SuperLongStringNotNull':
            default:
                return is_string($value);
        }
    }
    

    这会稍微减少您的CRAP 索引。但是,如果您使用的是 OO,您可能应该考虑使用 Strategy 模式,查看此处了解更多信息 https://phpenthusiast.com/blog/strategy-pattern-the-power-of-interface

    【讨论】:

      【解决方案3】:

      为了使您的代码更易于测试,请在每次类型检查之外创建对象方法。

      
      public function isTypeString($value) {
          return is_string($value);
      }
      
      public function isTypeLongStringNotNull($value) {
          return is_string($value);
      }
      

      现在您可以通过两种方式调用这些方法。你可以像以前一样将$type传递给typeCheck(),也可以使用一些神奇的方法或者直接调用isType...()方法

      // class Whatever
       /**
       * Check type of attribute value
       * @param $type
       * @param $value
       * @return bool
       */
      public function typeCheck($type, $value)
      {
          $this->value = $value;
          if (method_exists($this, 'isType'.ucfirst($type)) {
             return call_user_func([$this, 'isType'.ucfirst($type)], $value);
          }
          return this->isTypeString($value);
      }
      
      public function __call($method, $args) {
         return call_user_func_array( [$this, 'isType'.ucfirst($type)], $args);
      }
      // } class
      
      
      
      //3 ways to call the type check methods
      
      //regular way
      $x = new Whatever();
      $x->typeCheck('LongStringNotNull', $val);
      $x->isTypeLongStringNotNull($val);
      
      //magic __call
      $x->LongStringNotNull($val);
      
      //string interpolation
      $check = 'LongStringNotNull';
      $x->{$check}($val);
      $x->{'isType'.$check}($val);
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多