修复具有高NPath复杂度的代码


Fix code with high NPath complexity

当PHPMD报告我的一些代码具有高的NPath复杂度时,我正在用PHP Mess Detector分析我的代码。一个例子是:

function compareDates($date1, $date2){
    if($date->year < $date2->year){
        return -1;
    }
    if($date->year > $date2->year){
        return 1;
    }
    if($date->month < $date2->month){
        return -1;
    }
    if($date->month > $date2->month){
        return 1;
    }
    if($date->day < $date2->day){
        return -1;
    }
    if($date->day > $date2->day){
        return 1;
    }
    // etc.. same for hour, minute, second.
    return 0;
}

结果将是这个函数具有非常高的NPath复杂度。是否有一种通用的编码方法来减少这种控制结构和NPath的复杂性?

源代码:http://code.google.com/p/phpraise/source/browse/trunk/phpraise/core/datetime/RaiseDateTime.php#546

您的代码实际上是相对简单的,只是结构不佳。我建议创建一个子函数,它接受两个参数并处理-1/1的返回,然后遍历要检查的字段数组,因为这将更容易一些,但是有一些注意事项:

  1. 你的路没问题。它不干净,但很清楚,如果它能工作,就没有迫切需要改变它——任何程序员看到它都能理解你在做什么,即使他们嘲笑你的实现。

  2. 复杂性不是圣杯。这很重要,作为一个做过大量维护编程的程序员,我认为编写我维护的代码的人了解复杂性是非常重要的,但是你不能完全避免复杂性,有时复杂的解决方案(使用McCabe的复杂性)是最容易阅读的。

我真正建议你做的唯一改变是有一个单独的回电。执行如下命令:

$compare_val = 0;

在你的文件的顶部,然后改变你的后续if调用到elseifs,而不是返回值,只是更新$compare_val并返回它在你的函数结束。

认为排序函数必须返回-1,0,1是一个常见的误解。你可以做

function compareDates($date1, $date2)
{
    return strtotime("{$date1->year}-{$date1->month}-{$date1->day}")
         - strtotime("{$date2->year}-{$date2->month}-{$date2->day}");
}

注意,如果整数限制是一个问题,你可以使用DateTime,它没有这个限制,例如

function compareDates($date1, $date2)
{
    return new DateTime("{$date1->year}-{$date1->month}-{$date1->day}")
         < new DateTime("{$date2->year}-{$date2->month}-{$date2->day}");
}

一般来说,对于降低NPath复杂度,你必须减少可能的执行路径的数量。从Fowler的重构书中关于简化条件表达式的章节开始。

顺便说一下,我想知道RaiseDateTime的好处是什么?它能做任何原生DateTime API不能做的事情吗?如果没有,我为什么要使用它?

我新的PHP不做同样的代码,但只是简单?

function compareDates($date1, $date2){
if(($date->year < $date2->year) || ($date->month < $date2->month) || ($date->day < $date2->day) {
    return -1;
}
 if($date->year > $date2->year) || ($date->month > $date2->month) || ($date->day > $date2->day) {
    return 1;
}
// etc.. same for hour, minute, second.
return 0;
}