PHP, comment attraper une division par zéro?
j'ai une grande expression mathématique qui doit être créé dynamiquement. Par exemple, une fois que j'ai analysé "quelque chose" le résultat sera une chaîne comme: "$foo+$bar/$baz";
.
donc, pour calculer le résultat de cette expression j'utilise la fonction eval
... quelque chose comme ceci:
eval("$result = $expresion;");
echo "The result is: $result";
le problème ici est que parfois j'ai des erreurs qui disent qu'il y avait une division par zéro, et je ne sais pas comment attraper cette Exception. J'ai essayé des choses comme:
eval("try{$result = $expresion;}catch(Exception $e){$result = 0;}");
echo "The result is: $result";
ou:
try{
eval("$result = $expresion;");
}
catch(Exception $e){
$result = 0;
}
echo "The result is: $result";
mais ça ne marche pas. Alors, comment puis-je éviter que ma demande s'effondre alors qu'il y a une division par zéro?
Edit:
tout d'abord, je veux clarifier quelque chose: l'expression est construite dynamiquement, donc je ne peux pas simplement évaluer si le dénominateur est zéro. Si... en ce qui concerne le commentaire de Mark Baker, permettez-moi de vous donner un exemple. Mon analyseur pourrait construire quelque chose comme ceci:
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
l'analyseur construit la chaîne pas à pas sans se soucier de la valeur des var... donc dans ce cas si $foz == $bak
il y a en fait une division par zéro: $baz / ( 0 )
.
d'un autre côté comme Pete l'a suggéré, j'ai essayé:
<?php
$a = 5;
$b = 0;
if(@eval(" try{ $res = $a/$b; } catch(Exception $e){}") === FALSE)
$res = 0;
echo "$resn";
?>
mais il n'imprime rien.
12 réponses
if ($baz == 0.0) {
echo 'Divisor is 0';
} else {
...
}
plutôt que d'utiliser eval, ce qui est très dangereux si vous utilisez user-input dans l'expression évalée, pourquoi ne pas utiliser un analyseur approprié tel que evalmath sur PHPClasses , et qui soulève une exception nette sur diviser par zéro
Voici une autre solution:
<?php
function e($errno, $errstr, $errfile, $errline) {
print "caught!\n";
}
set_error_handler('e');
eval('echo 1/0;');
voir set_error_handler()
vous avez juste besoin de définir un gestionnaire d'erreurs pour lancer une exception en cas d'erreurs:
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();
comme d'autres l'ont mentionné, envisagez d'essayer une solution qui vous permettra de vérifier si le dénominateur est 0.
depuis que ce conseil semble inutile votre but, voici un peu d'information sur la gestion des erreurs PHP.
les premières versions de PHP n'avaient pas d'exceptions. À la place, des messages d'erreur de divers niveaux ont été émis (avis, avertissements, etc.). Une erreur Fatale s'arrête l'exécution.
PHP5 introduit des exceptions au tableau, et les nouvelles bibliothèques PHP fournies (PDO) vont lancer des exceptions lorsque des choses mauvaises/inattendues se produisent. Hoever, le codebase de base n'a pas été réécrit pour utiliser exception. Les fonctions de base et les opérations reposent toujours sur l'ancien système d'erreurs.
division par 0, vous obtenez un Avertissement, pas une exception
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
si vous voulez "attraper" ces, vous aurez besoin de définir un gestionnaire d'erreurs personnalisé qui détectera division par zéro erreurs et faire quelque chose à leur sujet. Malheureusement, les gestionnaires d'Erreurs Personnalisés sont un piège, ce qui signifie que vous aurez aussi besoin d'écrire un code pour faire quelque chose de APPROPRIÉ avec toutes les autres erreurs.
if(@eval("$result = $expresion;")===FALSE){
$result=0;
}
ne fera pas que diviser par 0 erreurs.
je faisais face à ce problème aussi (expressions dynamiques). Je l'ai fait de cette façon, ce qui n'est peut-être pas la meilleure, mais ça marche. Au lieu de lancer une Exception, vous pouvez bien sûr retourner null ou false ou ce que vous souhaitez. Espérons que cette aide.
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;
}
sur PHP7 vous pouvez utiliser DivisionByZeroError
try {
echo 1/0;
}
catch(DivisionByZeroError $e){
echo "got $e";
}
vous pouvez simplement attraper DivisionByZeroError
en PHP >= 7
utiliser un @
(un opérateur de contrôle d'erreur .) Ceci indique à php de ne pas afficher d'avertissements en cas d'erreurs.
eval("$result = @($expresion);");
if ($result == 0) {
// do division by zero handling
} else {
// it's all good
}
une chaîne contenant des nombres et les opérateurs mathématiques + - * / est passée comme entrée. Le programme doit évaluer la valeur de l'expression (selon BODMAS) et imprimer la sortie.
Exemple D'Entrée / Sortie: Si l'argument est "7 + 4*5" la sortie doit être de 27. Si l'argument est "55 + 21 * 11 - 6/0" la sortie "erreur" (Comme la division par zéro n'est pas défini).
problème:
b=1; c=0;
a=b/c;
// Error Divide by zero
Solution simple:
if(c!=0) a=b/c;
else // error handling
j'ai été aux prises avec cela aussi, les solutions set_error_handler
ne fonctionnaient pas pour moi, probablement basé sur des différences de version de PHP.
la solution pour moi était de tenter de détecter une erreur à l'arrêt:
// 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');
Je ne sais pas pourquoi une division par 0 est en train de s'arrêter plutôt que d'être gérée par le set_error_handler
mais cela m'a aidé à aller au-delà juste en mourant silencieusement.