2010-08-03 16 views
14

Eventuali duplicati:
is “else if” faster than “switch() case” ?"se" contro "switch"

Ho incontrato un sacco di situazioni ultimamente dove ho condizionali molto semplici e hanno bisogno di espandersi flusso applicativo. I "semplici" mezzi di realizzare quello che sto facendo è solo una pianura vecchio if/elseif dichiarazione:

if($value == "foo") { 
    // ... 
} elseif($value == "bar") { 
    // ... 
} elseif($value == "asdf" || $value == "qwerty") { 
    // ... 
} 

... ma sto considerando anche qualcosa di simile:

switch($value) { 
    case "foo": 
     // ... 
     break; 
    case "bar": 
     // ... 
     break; 
    case "qwer": 
    case "asdf": 
     // ... 
} 

Questo sembra un po 'meno leggibile, ma forse è più performante? Tuttavia, quando ci sono sempre più "o" espressioni nella condizionale, sembra che l'istruzione switch è molto più leggibile e utile:

switch($value) { 
    case "foo": 
     // ... 
     break; 
    case "bar": 
    case "baz": 
    case "sup": 
     // ... 
     break; 
    case "abc": 
    case "def": 
    case "ghi": 
     // ... 
     break; 
    case "qwer": 
    case "asdf": 
     // ... 
} 

Ho visto anche le opzioni in cui il flusso di codice è ramificata utilizzando gli array e funzioni:

function branch_xyz() {/* ... */} 
function branch_abc() {/* ... */} 
function branch_def() {/* ... */} 

$branches = array(
    "xyz"=>"branch_xyz", 
    "abc"=>"branch_abc", 
    "def"=>"branch_def" 
); 
if(isset($branches[$value])) { 
    $fname = $branches[$value]; 
    $fname(); 
} 

Quest'ultima opzione ha anche presumibilmente il vantaggio di essere distribuibile su più file, anche se è piuttosto brutto.

Quale ritiene abbia i maggiori vantaggi con il minor numero di compromessi in termini di prestazioni, leggibilità e facilità d'uso?

+1

uso di 'switch' è migliore nel tipo di situazione è stato specificato. – Sarfraz

+2

Le prestazioni non sono nemmeno un fattore decisivo. Scrivi prima il codice leggibile, poi il profilo e ottimizza se necessario in seguito. –

+0

Duplicato di un duplicato, ecc. Http://stackoverflow.com/questions/3387758/java-case-statment-or-if-statement-efficiency-perspective –

risposta

27

Personalmente, trovo l'interruttore molto più leggibile. Ecco il motivo:

if ($foo == 'bar') { 
} elseif ($foo == 'baz') { 
} elseif ($foo == 'buz') { 
} elseif ($fou == 'haz') { 
} 

condensato in quel modo, si può facilmente vedere il viaggio fino (che si tratti di un errore di battitura, o di una differenza onesti). Ma con un interruttore, si sa implicitamente quello che doveva:

switch ($foo) { 
    case 'bar': 
     break; 
    case 'baz': 
     break; 
    case 'buz': 
     break; 
    case 'haz': 
     break; 
} 

Plus, che è più facile da leggere:

if ($foo == 'bar' || $foo == 'baz' || $foo == 'bat' || $foo == 'buz') { 
} 

o

case 'bar': 
case 'baz': 
case 'bat': 
case 'buz': 
    break; 

Dal punto di vista delle prestazioni ... Bene , non preoccuparti per le prestazioni. A meno che non ne facciate alcune migliaia all'interno di un circuito chiuso, non sarete nemmeno in grado di dire la differenza (la differenza sarà probabilmente nella gamma dei microsecondi, se non inferiore).

Scegli il metodo che ritieni più leggibile. Questa è la parte importante. Non provare a micro-ottimizzare. Ricorda, Premature Optimization Is The Root Of All Evil ...

+1

Fai attenzione che questo interruttore ti fornisca ** falsi ** negativi e falsi positivi a causa di [confronto casuale] (http://stackoverflow.com/q/3525614/632951). Qui, 'switch' è un odore di codice e la rovina della sicurezza ipso facto. Usa invece i tasti dell'array. – Pacerier

+0

@Pacerier, perché il passaggio è un pericolo per la sicurezza? –

+3

@ ryabenko-pro, il confronto libero vi darà dei piccoli bug: 'switch (0) {case null: echo 'null'; rompere; default: echo 'not null';} ' – Pacerier

1

Switch indica ai lettori successivi che si sta eseguendo la ramificazione in base al valore di un singolo valore, che dovrebbero implicare altrimenti osservando tutte le condizioni. Quindi preferirei l'interruttore per chiarezza

44

Lo so, la micro-ottimizzazione è male.Ma curioso come lo sono io, ho fatto un po 'di riferimento utilizzando questo script:

<?php 
$numof = 100000; 
$file = fopen('benchmark.php', 'w'); 
if (!$file) die('file error'); 
fwrite($file, '<pre><?php' . "\n" . 'echo $i = $_GET[\'i\'], "\n";' . "\n"); 

fwrite($file, 
'$start = microtime(true); 
if ($i == 0) {}' . "\n"); 
for ($i = 1; $i < $numof; ++$i) { 
    fwrite($file, 'elseif($i == '.$i.') {}'. "\n"); 
} 
fwrite($file, 
'echo \'elseif took: \', microtime(true) - $start, "\n";' . "\n"); 

fwrite($file, 
'$start = microtime(true); 
switch($i) {' . "\n"); 
for ($i = 1; $i < $numof; ++$i) { 
    fwrite($file, 'case '.$i.': break;'. "\n"); 
} 
fwrite($file, 
'} 
echo \'switch took: \', microtime(true) - $start, "\n";' . "\n"); 

I dati risultanti (per numof = 100000):

i: 0 
elseif took: 6.2942504882812E-5 
switch took: 3.504753112793E-5 

i: 10 
elseif took: 6.4849853515625E-5 
switch took: 4.3869018554688E-5 

i: 100 
elseif took: 0.00014805793762207 
switch took: 0.00011801719665527 

i: 1000 
elseif took: 0.00069785118103027 
switch took: 0.00098896026611328 

i: 10000 
elseif took: 0.0059938430786133 
switch took: 0.0074150562286377 

i: 100000 (first non-existing offset) 
elseif took: 0.043318033218384 
switch took: 0.075783014297485 

stato eseguito lo script sulla mia macchina Windows vecchio e lento con PHP 5.3.1 o 5.3.2, non so bene.

+10

+1 per fare qualcosa per tentare effettivamente di misurare la differenza di prestazioni per dare una risposta valida a ciò che la domanda richiede. – Kmeixner