我刚写了一个可怕的PHP函数,我需要一些帮助(elseif chain - switch?)

时间:2009-11-13 19:41:55

标签: php optimization

我正在制作一个网站,根据时间确定数组的值。我写了这个糟糕的(功能)脚本,我想知道我是否可以让它更简洁。我开始使用case / switch语句,但是在使用多个条件时遇到了麻烦。这是肮脏的行为:

if ($now < november 18th) {
    $array_to_use = $home;
}
elseif (november 18th < $now && $now < november 21st ) {
    $array_to_use = $driving;
}
elseif (november 21st < $now && $now < november 22nd) {
    $array_to_use = $flying;
}
...
...
...
elseif (february 1st < $now) {
    $array_to_use = $arrived;
}
else {
    $array_to_use = $default;
}

计划实际上更复杂,并且其中包含13个elseif语句。有人可以确认我刚刚编写了编码器块并且有更好的方法吗?

编辑:我将Unix时间戳更改为粗略的实际时间,因此更容易理解我在做什么(希望如此)

编辑2:请原谅当前损坏的Javascript时钟,但这是我正在处理的网站:

Time Table

每个阵列都基于我的位置,并且根据它的时间有15个“它们当前”。这是一个具有已知开始/结束时间的小问题域,因此灵活性不是关键,只需将其全部写入。您可以看到时间是如何连续的,并且一次只需要选择一个字符串数组。

6 个答案:

答案 0 :(得分:13)

首先,请请取出你的硬编码并将它们放入常数中。

$FLIGHT_START_TIME = 1258956001;
$FLIGHT_END_TIME   = 1260511201;

其次,我会为每个条件制作迷你函数:

即。

function isFlying($time)
{
    return ( $FLIGHT_START_TIME < $time && $time < $FLIGHT_END_TIME );
}

第三,拿出你的整套条件,并把它放到一个函数中来获取你当前的状态,并在你的函数调用中替换:

function getStateArrayForTime($time)
{

   if (isDriving($time)
   {
       return $driving;
   }
   if ( isFlying($time) )
   {
        return $flying;
   }
...etc
}

最后,用单个函数调用替换代码的整个内联部分:

$currentState = getStateArrayForTime($now);

正如其他海报也评论过的那样,此时你可以使用数据表驱动函数来返回状态,如果你知道只有开始和结束时间将是状态参数:

所以用以下代码替换getStateArrayForTime的实现:

function getStateArrayForTime ($time)
{
// 
$states = array (
    array("startTime" => 1258956001, "endTime" => 1260511201, "state" => $flying),
    array("startTime" => 1260511201, "endTime" => 1260517000, "state" => $driving),
..etc...
);
    foreach($states as $checkStateArray)
    {
        if($checkStateArray['startTime'] < $time && $time < $checkStateArray['endTime'])
        {
            return $checkStateArray['state'];
        }
    }
    return null;
}

最后,有些人可能会问“为什么按此顺序做事?”除了在应用程序中,我根本不能要求信用,但Martin Fowler有一本名为“Refactoring”的好书解释了为什么你一步一步地清理代码,并在每一步测试,然后最后替换那些没有意义的功能批发,同时测试它们在功能上是否相同。

答案 1 :(得分:7)

这可能有点矫枉过正,但我​​会做这样的事情,以便我可以将所有时间范围放在一个明确的位置:

@timeWindows = ({ start -> 0, end -> 1258783201, array -> $home },
                ... ,
                {start -> 1260511201, end -> MAXVAL, array -> $arrived});

然后像

这样的循环
$array_to_use = $default;

foreach (my $window in @timeWindows) {
   if (($now > $window->start) && ($now < $window->end)) {
       $array_to_use = $window->array;
       last;
   }
}

对不起它在Perl,我不懂PHP,但我想它类似。

答案 2 :(得分:3)

您可以将时间和数组用于数组并循环选择。

$Selctions = array(
    1258783201 => $Home,
    1258956001 => $Driving,
    1260511201 => $Flying,
    ...
    1260511201 => $Arriving
);

// MUST SORT so that the checking will not skip
ksort($Selction);
$TimeToUse = -1;
$Now       = ...;
foreach ($Selctions as $Time => $Array) {
    if ($Now < $Time) {
        $TimeToUse = $Time;
        break;
    }
}
$ArrayToUse = ($TimeToUse != -1) ? $Selctions[$TimeToUse] : $Default;

此方法只能在时间没有间隙(一个接一个的范围)时使用。

希望这有帮助。

答案 3 :(得分:2)

您可以使用switch语句,执​​行以下操作:

switch (true)
{
    case $now < 1258783201:
        // your stuff
        break;
    case $now < 1258783201
        // more of your stuff
        break;
    //...
}

至少有点干净......

答案 4 :(得分:0)

这样的事情:

$array_to_use = null;
$dispatch = array(1258783201, $home, 1258956001, $driving, ..., $arrived);
for ($i=0; i<count($dispatch); $i+=2) {
    if ($now<$dispatch[$i]) {
        $array_to_use = $dispatch[$i+1];
        break;
    }
}
if ($array_to_use==null) $array_to_use = $dispatch[count($dispatch)-1];

您还需要考虑是否需要“&lt;”或“&lt; =”condition。

答案 5 :(得分:0)

您可能想学习命令模式;它也可以在这种情况下提供帮助。