2013-03-24 13 views
8

stavo refactoring qualche vecchio codice quando sono incappato in un costrutto simile a questo:Sostituzione di IF con un'espressione logica in PHP

// function bar() returns a value 
// if the value is an instance of customException class, terminate with error code 
// else process the regular data 

$foo = bar(); 
checkForException($foo) && exit($foo->errorCode()); 
process($foo); 

Ora per quanto strano possa sembrare, questo è molto più breve poi

$foo=bar(); 
if(checkForException($foo)) { 
    exit($foo->errorCode(); 
} 
else { 
    process($foo); 
} 

e un po 'più leggibile (almeno dopo la sorpresa iniziale) poi

$foo=bar(); 
(checkForException($foo)) ? exit($foo->errorCode()) : process($foo); 

Mentre il codice più corto non significa necessariamente un codice più leggibile, trovo che si trovi da qualche parte nel mezzo dei due modi "standard" sopra.

In altre parole, invece di

if($foo) { 
    bar(); 
} 
else { 
    // there is no real reason for this to exist, since 
    // I have nothing to write here, but I want to conform 
    // to the general coding practices and my coding OCD 
} 

Si potrebbe semplicemente scrivere

$foo && bar(); 

Allora, qual è il ragionamento dietro questo non vedendo molto uso? Può essere semplice come "Non reinventare la ruota, scrivi il più leggibile se/else, e se vuoi davvero accorciarlo, questo è l'operatore ternario"?

MODIFICA: tenere presente che il codice sopra riportato è stato rapidamente derivato dal codice originale e intendeva essere solo un esempio dell'uso del codice "cortocircuito". Se puoi, ti preghiamo di non suggerire miglioramenti del codice, poiché quello non era il risultato desiderato della domanda.

Esempio n ° 2

userCheckedTheBox($user) && displayAppropriateInfo(); 
+1

In un framework strutturato, non si userà 'exit' tanto. Oltre a ciò, un pieno 'if/else' ti permette di usare più istruzioni nel ramo' else' - comunque a volte il cortocircuito è molto molto utile, ma non abusarne. – moonwave99

+0

Perché dovrebbe essere "strano" (come in "strano come potrebbe sembrare") che meno caratteri sono più brevi di più caratteri? Devi vivere una vita protetta. –

+0

"Allora, qual è il ragionamento alla base di questo non vedere molto uso?" --- perché ci sono diversi tipi di programmatori: alcuni scrivono codice "cool", un altro - facile da supportarne uno. – zerkms

risposta

3

C'è una vecchia tecnica che credo fosse popolare negli script perl hacked-together per mostrare errori. pseudo-codice:

myFunction() || exitWithError("Uh-oh") 

Quando codifica-a-un-termine, e quando l'interfaccia utente non ha bisogno di essere stellare, si tratta di un modo rapido per evitare errori.

Lo stile è popolare anche in javascript per i parametri di default:

function myfunction(foo) { 
    foo = foo || 0; 
    // note that a non-zero default won't work so well, 
    // because the user could call the function with 0 
} 

e per nulli Autocontrollo:

var bar = foo && foo.property; 

Trovo che una volta che si è abituati ad esso, è molto leggibile e spesso più intuitivo di if/else o ?:. Ma dovresti usarlo solo quando ha senso. Usarlo ovunque diventerà molto confuso. Ad esempio, nel tuo esempio, devi utilizzare non. Personalmente lo uso per il semplice controllo degli errori e per i valori di default . Nei progetti grandi, quasi sempre si vuole fare molto di più quando si verifica un errore, quindi in questi casi non si dovrebbe usare questo.

Inoltre dovresti stare attento; funziona solo in lingue con valutazione di cortocircuito (http://en.wikipedia.org/wiki/Short-circuit_evaluation). E a volte and e or sono in cortocircuito, mentre non lo sono && e ||.

myfunction() or die("I'm melting!"); è anche abbastanza soddisfacente per scrivere.

Infine, i blocchi else vuoti di solito sono qualcosa che non ho mai visto prima, o che nessuno ha mai sentito raccomandare. Sembra molto inutile per me. L'opzione più leggibile per il tuo esempio è, semplicemente:

if($foo) { 
    bar(); 
} 
6

Mentre $foo && bar(); è un minor numero di linee di codice è molto meno leggibile. Rendere il tuo codice facile da capire è solitamente più importante della riduzione del LoC totale. Anche se non stai lavorando in un ambiente con più programmatori, dovrai tornare a leggere il tuo codice in futuro, e probabilmente non sarai in grado di ricordare quale fosse la logica dietro ogni linea di codice (Eagleson's Law).

In genere, è necessario limitare l'uso di questo tipo di istruzioni solo ai casi in cui l'intento del programmatore è assolutamente chiaro. A mio parere, è una pratica molto brutta avere un codice che testa una condizione e un codice che modifichi attivamente lo stato corrente del programma sulla stessa istruzione.

Ecco uno uso accettabile per questo tipo di codice:

$isValidUser = $userName && usernameIsValid(); 

Qui, entrambi i lati del operatore && stanno sperimentando una condizione, il fatto che il lato destro chiama una funzione per fare che non nuocere la leggibilità del codice.

1

Per gli errori si dovrebbe usare vere eccezioni:

try { 
    $foo = bar(); 
} catch(FooException $e) { 
    exit($e->errorCode); 
} 
process($foo); 

Vedi the documentation for errorhandling.

+1

OP_is_ utilizzando le eccezioni reali ('customException'), non vengono semplicemente lanciati, ma usati come ritorno valore ... –

1

Che cosa fa quel codice, restituendo un'istanza di CustomException non si sommano.Perché non cambiare la definizione della funzione un po ':

function bar() 
{ 
    $stuff = true; 
    if ($stuff === true) 
    { 
     return 'Value on success'; 
    } 
    //something went wrong: 
    throw new CustomException('You messed up'); 
} 
try 
{//here's the outlandish try-catch block 
    $foo = bar(); 
} 
catch (CustomException $e) 
{ 
    exit($e->message());//fugly exit call, work on this, too 
} 
//carry on here, no exception was thrown 

Inoltre, chiamando che seconda funzione (checkForException($foo)) è semplicemente assurdo. Le chiamate di funzione sono economiche, ma non gratuite. Vuoi sapere se la funzione ha restituito un'istanza di CustomException? Non trasformarlo in una funzione, ma utilizzare instanceof. Usare il cortocircuito per mantenere basso il numero di caratteri (ad esempio in fase di analisi), mentre allo stesso tempo sprecare risorse su tutti gli altri livelli è sciocco come comparire in un mustang V8 su un percorso iper-miling.

+0

Ho modificato la mia domanda per riflettere meglio il risultato desiderato. Le eccezioni vengono lanciate e gestite, i nomi sono solo un po 'sfortunati. – user1853181

+0

@ user1853181: Mi spiace continuare a sbattere così, ma chiaramente non stai facendo un'eccezione. Se lo fosse, la valutazione di cortocircuito fallirebbe e tutto ciò che vedresti è un messaggio che dice "Errore: Eccezione non rilevata" –

+0

Per quanto ho capito, il gestore di eccezioni in bar() registra le informazioni sulle eccezioni e restituisce il oggetto personalizzato (con un codice di errore tra le altre informazioni) al chiamante. Sono sicuro che c'era una buona intenzione, cercando di capirlo subito ... Ma questo è davvero un argomento per un'altra domanda, se ne sorge la necessità. – user1853181

0

Un'altra possibile soluzione per il vostro problema:

$foo = bar(); 
!checkForException($foo) or exit($foo->errorCode); 
process($foo); 

Ma meglio cambiamento !checkForException per isNoException o qualcosa del genere.