2010-06-18 20 views
24

Ho una grande espressione matematica che deve essere creata dinamicamente. Ad esempio, dopo aver analizzato "qualcosa" il risultato sarà una stringa come: "$foo+$bar/$baz";.PHP, Come prendere una divisione per zero?

Quindi, per calcolare il risultato di tale espressione sto usando la funzione eval ... qualcosa di simile:

eval("\$result = $expresion;"); 
echo "The result is: $result"; 

Il problema qui è che a volte si verificano errori che dice che c'è stata una divisione per zero, e non so come catturare quell'eccezione. Ho provato cose come:

eval("try{\$result = $expresion;}catch(Exception \$e){\$result = 0;}"); 
echo "The result is: $result"; 

Oppure:

try{ 
    eval("\$result = $expresion;"); 
} 
catch(Exception $e){ 
    $result = 0; 
} 
echo "The result is: $result"; 

Ma non funziona. Quindi, come posso evitare che la mia applicazione si chiuda in modo anomalo quando c'è una divisione per zero?

Edit:

In primo luogo, voglio chiarire una cosa: l'espressione è costruita in modo dinamico, quindi non posso solo eval se il denominatore è zero. Quindi ... per quanto riguarda il commento di Mark Baker, lasciatemi fare un esempio. Il mio parser potrebbe costruire qualcosa di simile:

"$foo + $bar * ($baz/($foz - $bak))" 

Il parser costruire passo dopo passo stringa senza preoccuparsi del valore delle Vars ... quindi in questo caso, se $foz == $bak c'è infatti una divisione per zero: $baz/(0).

D'altra parte, come ha suggerito Pete, ho provato:

<?php 
$a = 5; 
$b = 0; 

if(@eval(" try{ \$res = $a/$b; } catch(Exception \$e){}") === FALSE) 
     $res = 0; 
echo "$res\n"; 
?> 

Ma non stampa nulla.

+1

Potete controllare se '$ expression' sta dividendo per zero anticipo? –

+0

@Anthony Forloney: Bella domanda, la mia risposta ha creduto che potessi, ma se Cristian sta davvero usando eval per questo, allora la risposta è probabilmente "no". – Powerlord

+2

L'uso di 'eval' può essere una cattiva idea. Ora lascerai che il tuo utente finale esegua il codice PHP sul tuo server.Non conosco un'alternativa, quindi non sto inviando una risposta, ma dovresti pensare se vuoi che io sia in grado di digitare qualsiasi codice PHP, non importa quanto sia distruttivo nella tua pagina web. – Umang

risposta

15
if ($baz == 0.0) { 
    echo 'Divisor is 0'; 
} else { 
    ... 
} 

Piuttosto che utilizzare eval, che è altamente pericoloso se si sta utilizzando gli input degli utenti all'interno dell'espressione evalled, perché non utilizzare una corretta parser, come evalmath on PHPClasses, e che solleva un'eccezione pulito sulla divisione per zero

+0

No ... come ho detto l'espressione è costruita dinamicamente. Se fosse un'espressione statica sarebbe davvero facile, ma non lo è. – Cristian

+4

Come viene generato dinamicamente? Deve essere "costruito" in qualche modo dal tuo "parser" ... ea quel punto dovresti essere in grado di identificare se il divisore è 0 o no! –

+0

Questo dovrebbe funzionare se si sostituisce $ baz con eval ("\ $ result = $ baz;") e quindi test è $ result è 0 o meno. – vad

2
if(@eval("\$result = $expresion;")===FALSE){ 
    $result=0; 
} 

Non si limiterà a rilevare dividi per 0 errori.

+0

+1, ma invece di * $ risultato = 0; * utilizzare * $ result = "#error"; * o generare un'eccezione. – ern0

+0

eval è il male! Si prega di NON utilizzare –

6

Ecco un'altra soluzione:

<?php 

function e($errno, $errstr, $errfile, $errline) { 
    print "caught!\n"; 
} 

set_error_handler('e'); 

eval('echo 1/0;'); 

Vedi set_error_handler()

+0

"Non è possibile rilevare un errore di analisi in eval() utilizzando set_error_handler()" http://www.php.net/manual/en/function.eval.php – Pete

+4

@Pete: Right ma l'OP chiedeva di dividere per zero errori, non di analizzare errori. Ho testato lo script di cui sopra e rileva l'errore. –

0

Utilizzare un @ Questo dice a PHP di non avvertenze di uscita in caso di errori (An error control operator.).

eval("\$result = @($expresion);"); 
if ($result == 0) { 
    // do division by zero handling 
} else { 
    // it's all good 
} 
+0

Non va bene. Cosa succede se '$ expression =" 0/5 "'? Allora hai un falso positivo. –

+0

La divisione per zero restituisce effettivamente 'false', non 0. Prova invece' $ result === false'. – Hubro

3

Come altri hanno detto, prendere in considerazione cercando una soluzione che vi permetterà di controllare se il denominatore è 0.

Da quel consiglio sembra inutile il vostro scopo, ecco un po 'di storia sulla gestione degli errori di PHP.

Le versioni precedenti di PHP non hanno eccezioni. Invece, sono stati sollevati messaggi di errore di vari livelli (Avvisi, Avvisi, Ecc.). Un errore irreversibile interrompe l'esecuzione.

PHP5 ha portato eccezioni alla tabella e le nuove librerie (PDO) fornite da PHP generano eccezioni quando accadono cose brutte/inattese. Hoever, il corebase principale NON è stato riscritto per usare l'eccezione. Le funzioni e le operazioni principali si basano ancora sul vecchio sistema di errori.

Se si divide da 0, si ottiene un avvertimento, non un'eccezione

PHP Warning: Division by zero in /foo/baz/bar/test.php(2) : eval()'d code on line 1 
PHP Stack trace: 
PHP 1. {main}() /foo/baz/bar/test.php:0 
PHP 2. eval() /foo/baz/bar/test.php:2 

Se si vuole "catturare" questi, avrete bisogno di set a custom error handler che rileverà la divisione per zero errori e fare qualcosa su di loro. Sfortunatamente, i gestori di errori personalizzati sono un catch all, il che significa che dovrai anche scrivere del codice per fare qualcosa di appropriato con tutti gli altri errori.

+0

Ricevo un errore irreversibile con PHP 5.6. Non un avvertimento. – MightyPork

+0

non importava che il mio Framework faceva qualcosa di veramente ritardato con set_error_handler() – MightyPork

2

Mi trovavo di fronte anche a questo problema (espressioni dinamiche). Idid in questo modo che potrebbe non essere il modo più bello ma funziona. Invece di lanciare un'eccezione puoi ovviamente restituire null o false o qualsiasi altra cosa desideri. Spero che questo ti aiuti.

function eval_expression($expression) 
{ 
    ob_start(); 
    eval('echo (' . $expression . ');'); 
    $result = ob_get_contents(); 
    ob_end_clean(); 
    if (strpos($result, 'Warning: Division by zero')!==false) 
    { 
     throw new Exception('Division by zero'); 
    } 
    else return (float)$result; 
} 
0

Una stringa contenente numeri e gli operatori matematici + - */viene trasmessa come input. Il programma deve valutare il valore dell'espressione (come per BODMAS) e stampare l'output.

Esempio Input/Output: Se l'argomento è "7 + 4 * 5" l'uscita deve essere 27. Se l'argomento è "55 + 21 * 11 - 6/0" l'uscita deve essere "errore" (Poiché la divisione per zero non è definita).

3

Hai solo bisogno di impostare un gestore di errori un'eccezione in caso di errori:

set_error_handler(function() { 
    throw new Exception('Ach!'); 
}); 

try { 
    $result = 4/0; 
} catch(Exception $e){ 
    echo "Divide by zero, I don't fear you!".PHP_EOL; 
    $result = 0; 
} 

restore_error_handler(); 
0

Problema:

b=1; c=0; a=b/c; // Error Divide by zero

Soluzione semplice:

if(c!=0) a=b/c; 
else // error handling 
0

I Ho avuto anche questo problema, le soluzioni set_error_handler non funzionavano per me, probabilmente basato su differenze di versione di PHP.

La soluzione per me è stato quello di tentare di rilevare un errore di arresto:

// Since set_error_handler doesn't catch Fatal errors, we do this 
function shutdown() 
{ 
    $lastError = error_get_last(); 
    if (!empty($lastError)) { 
     $GLOBALS['logger']->debug(null, $lastError); 
    } 
} 
register_shutdown_function('shutdown'); 

io non sono sicuro perché una divisione per 0 si sta spegnendo, invece di essere gestita dal set_error_handler ma questo mi ha aiutato a ottenere al di là semplicemente morendo silenziosamente.

1

Su PHP7 è possibile utilizzare DivisionByZeroError

try { 
    echo 1/0; 
} 
catch(DivisionByZeroError $e){ 
    echo "got $e"; 
} 
Problemi correlati