2009-11-13 13 views
10

Estoy haciendo un sitio que determina el valor de una matriz en función de la hora que sea. Escribí este guión horrible (funcional), y me pregunto si podría haberlo hecho más conciso. Comencé con una declaración de caso/cambio, pero tuve problemas para obtener múltiples condicionales trabajando con ella. Aquí está el trabajo sucio:Acabo de escribir una función PHP horrible, necesito un poco de ayuda (elseif chain-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; 
} 

El horario es de hecho más complicado y tiene 13 elseif declaraciones en el mismo. ¿Alguien puede confirmar que acabo de bloquear el codificador y que hay una forma mejor de hacerlo?

EDIT: he cambiado el Unix marcas de tiempo a los tiempos reales difíciles, por lo que es más fácil de entender lo que estoy haciendo (con suerte)

EDIT 2: Por favor, perdona el reloj Javascript Actualmente roto, pero esto es el sitio en el que estoy trabajando:

Time Table.

Cada matriz se basa en mi ubicación, y hay 15 "actualmente" en función de la hora. Es un dominio de problemas pequeños con tiempos de inicio/finalización conocidos, por lo que la flexibilidad no es la clave, simplemente escribir todo. Puede ver cómo el tiempo es continuo, y solo se necesita seleccionar una matriz de cadenas a la vez.

+1

¿Hay cálculos matemáticos para las marcas de tiempo elegidas? –

+0

Hay matemáticas, sí. $ ahora se divide y redondea unas pocas veces –

+0

¿Cuántas condiciones? ¿Se superponen, o cada condición es exclusiva? –

Respuesta

13

En primer lugar, por favor por favor por favor saque sus números codificados y ponerlas en constantes.

$FLIGHT_START_TIME = 1258956001; 
$FLIGHT_END_TIME = 1260511201; 

En segundo lugar, me gustaría hacer mini funciones para cada uno de los condicionales:

es decir,

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

En tercer lugar, llevar a toda su conjunto de condicionales, y ponerlo en una función para obtener su estado actual, y vuelva a colocar en su función llama:

function getStateArrayForTime($time) 
{ 

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

pasado, sustituir toda la sección en línea de código con su llamada a una función única:

$currentState = getStateArrayForTime($now); 

Como otros también han comentado, en este punto se puede utilizar una tabla de datos de la función impulsado para volver al estado si usted sabe sólo el comienzo y el tiempo final será los parámetros de estado:

así reemplazar la implementación de getStateArrayForTime con: "¿por qué hacer las cosas en este orden"

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; 
} 

Por último, algunas personas pueden preguntar No puedo reclamar ningún crédito, excepto en la aplicación, pero Martin Fowler tiene un gran libro llamado "Refactorización" que explica por qué limpia el código paso a paso y prueba en cada paso del camino, y finalmente Reemplace las funciones al por mayor que no tienen sentido, mientras prueba que son funcionalmente equivalentes.

+1

Eso es todo un gran consejo. Verboso, pero limpio. Soy un pirata. ¡Gracias! –

+2

El problema es que si terminas en 200 estados más tienes 200 funciones más (ya tiene hasta 13). Agregar más estados no debería aumentar el código, solo un bloque de datos (preferiblemente externo). –

+0

También puede hacer que $ FLIGHT_START_TIME = 1258956001; $ FLIGHT_END_TIME = 1260511201; dinámico si también necesitaba esa flexibilidad, en lugar de codificar estas fechas/horas –

2

Se puede utilizar una sentencia switch, haciendo algo como esto:

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

Eso es, al menos, un poco más limpio ...

0

Algo como esto:

$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]; 

También necesita pensar acerca de si necesita "<" o "< =" condición.

+1

Creo que este código es asqueroso, pero no lo votará negativamente. ¿Por qué no poner su conjunto de elementos en un formato claramente legible? o use 2 arreglos separados? – Zak

7

Podría ser una exageración, pero yo hubiera hecho algo como esto para que yo pudiera poner todos los intervalos de tiempo en un punto claro:

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

y luego un bucle como

$array_to_use = $default; 

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

Lo siento, está en Perl, no sé PHP, pero me imagino que es similar.

+1

Esta es la mejor respuesta porque permite que los límites de tiempo se determinen programáticamente. No está claro si el OP lo requiere, pero es difícil imaginar un código útil que no lo haga. –

+0

Gracias. Parece que la respuesta a la cabeza acaba de modificarse para parecerse a la mía, así que supongo que no eres el único en pensarlo. :) –

3

Puede poner el tiempo y la matriz para utilizar en una matriz y hacer un bucle para seleccionar.

$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;

Este método sólo se puede utilizar cuando los tiempos tiene ningún hueco (un rango detrás de la otra).

Espero que esto ayude.

0

Es posible que desee aprender el Patrón de comando; también puede ayudar en esta circunstancia.

Cuestiones relacionadas