用于减少圈复杂度的太多开关案例的替代方案?
Alternative for too many switch case for cyclomatic complexity reduction?
我有一个函数可以检查 $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);
}
}
有更好的方法吗?
好吧,您可以将具有相同功能的那些分组:
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
您可以用数据结构替换开关:
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);
}
}
为了使您的代码更易于测试,请为每个类型检查创建对象方法。
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);
我有一个函数可以检查 $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);
}
}
有更好的方法吗?
好吧,您可以将具有相同功能的那些分组:
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
您可以用数据结构替换开关:
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);
}
}
为了使您的代码更易于测试,请为每个类型检查创建对象方法。
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);