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.

25
demandé sur Eric Leschinski 2010-06-18 19:41:01

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

16
répondu Mark Baker 2011-02-24 18:06:49

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()

6
répondu Bill Karwin 2010-06-18 15:47:45

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();
4
répondu tacone 2015-02-02 15:56:58

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.

3
répondu Alan Storm 2010-06-18 16:23:44
if(@eval("$result = $expresion;")===FALSE){
  $result=0;
}

ne fera pas que diviser par 0 erreurs.

2
répondu Pete 2010-06-18 15:45:18

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;
}
2
répondu Christopher Fox 2010-08-22 11:48:38

sur PHP7 vous pouvez utiliser DivisionByZeroError

try {
    echo 1/0;
}
catch(DivisionByZeroError $e){
    echo "got $e";
}
2
répondu David L 2017-09-28 16:10:09

vous pouvez simplement attraper DivisionByZeroError en PHP >= 7

voir http://php.net/manual/en/class.divisionbyzeroerror.php

1
répondu simPod 2016-12-16 13:08:41

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
}
0
répondu ghoppe 2010-06-18 15:53:25

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).

0
répondu dinesh 2013-07-17 12:07:12

problème:

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

Solution simple:

if(c!=0) a=b/c;
else // error handling
0
répondu user3557421 2015-11-19 15:06:53

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.

0
répondu justin.m.chase 2016-12-12 21:54:10