2010-06-18 59 views
24

Tengo una gran expresión matemática que debe crearse dinámicamente. Por ejemplo, una vez que haya analizado "algo" el resultado será una cadena como: "$foo+$bar/$baz";.PHP, ¿Cómo atrapar una división por cero?

Por lo tanto, para el cálculo del resultado de esa expresión que estoy usando la función eval ... algo como esto:

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

El problema aquí es que a veces recibo mensajes de error que dice que hubo una división por cero, y no sé cómo atrapar esa excepción. He tratado de cosas como:

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

O:

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

Pero no funciona. Entonces, ¿cómo puedo evitar que mi aplicación falle cuando hay una división por cero?

Editar:

En primer lugar, quiero aclarar algo: la expresión se construye de forma dinámica, por lo que no se puede simplemente eval si el denominador es cero. Entonces ... con respecto al comentario de Mark Baker, permítanme darles un ejemplo. Mi analizador podría construir algo como esto:

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

El analizador construir la etapa de colocación sucesiva a paso sin preocuparse por el valor de los VARs ... por lo que en este caso si $foz == $bak hay de hecho una división por cero: $baz/(0).

Por otra parte como se sugiere Pete, he intentado:

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

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

Pero no imprime nada.

+1

Se puede comprobar si '$ expression' está dividiendo por cero de antemano? –

+0

@Anthony Forloney: Buena pregunta, mi respuesta asumió que podrías, pero si Cristian está realmente usando eval para esto, entonces la respuesta es probablemente "no". – Powerlord

+2

Usar 'eval' puede ser una mala idea. Ahora permitirá que su usuario final ejecute código PHP en su servidor.No conozco ninguna alternativa, así que no estoy publicando una respuesta, pero debes pensar si quieres que escriba cualquier código PHP, sin importar cuán destructivo sea tu sitio web. – Umang

Respuesta

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

En lugar de utilizar eval, que es altamente peligroso si usted está utilizando la entrada de usuario dentro de la expresión evalled, por qué no utilizar un programa de análisis adecuado, como evalmath on PHPClasses y que plantea una excepción limpia de división por cero

+0

No ... como dije, la expresión está construida dinámicamente. Si fuera una expresión estática, sería muy fácil, pero no lo es. – Cristian

+4

¿Cómo se construye de forma dinámica? Debe ser "construido" de alguna manera por tu "analizador sintáctico" ... ¡y en ese punto deberías poder identificar si el divisor es 0 o no! –

+0

Esto debería funcionar si reemplaza $ baz con eval ("\ $ result = $ baz;") y luego la prueba es $ result es 0 o no. – vad

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

No obstante, no solo dividir por 0 errores.

+0

+1, pero en lugar de * $ resultado = 0; * use * $ result = "#error"; * o arroje una excepción. – ern0

+0

eval es malo! NO use –

6

Aquí hay otra solución:

<?php 

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

set_error_handler('e'); 

eval('echo 1/0;'); 

Ver set_error_handler()

+0

"No es posible detectar un error de análisis en eval() usando set_error_handler()" http://www.php.net/manual/en/function.eval.php – Pete

+4

@Pete: Right , pero el OP estaba preguntando acerca de la división por errores cero, no errores de análisis. Probé el script anterior y capta el error. –

0

Utilice un @ Esto le dice a PHP para no emitir avisos en caso de errores (Un error control operator.).

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

No es bueno. ¿Qué pasa si '$ expression =" 0/5 "'? Entonces tienes un falso positivo. –

+0

La división por cero realmente devuelve 'falso', no 0. Pruebe' $ result === false' en su lugar. – Hubro

3

Como otros han mencionado, considere intentar una solución que le permitirá comprobar si el denominador es 0.

Desde ese consejo parece inútil su propósito, aquí hay un poco de historia sobre el manejo de errores PHP.

Las primeras versiones de PHP no tenían excepciones. En cambio, se generaron mensajes de error de varios niveles (avisos, advertencias, etc.). Un error fatal detiene la ejecución.

PHP5 trajo excepciones a la tabla, y las últimas librerías proporcionadas por PHP (PDO) lanzarán excepciones cuando sucedan cosas malas/inesperadas. Sin embargo, el código base del núcleo NO fue reescrito para usar la excepción. Las funciones principales y las operaciones aún se basan en el antiguo sistema de error.

Cuando divide por 0, se obtiene una advertencia, no una excepción

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 usted quiere "atrapar" éstos, usted tendrá que set a custom error handler que detectará la división por cero errores y hacer algo a cerca de ellos. Desafortunadamente, los manejadores de errores personalizados son una trampa, lo que significa que también necesitará escribir algún código para hacer algo apropiado con todos los demás errores.

+0

Recibo un error fatal con PHP 5.6. No es una advertencia. – MightyPork

+0

nunca fue mi Framework haciendo algo realmente retardado con set_error_handler() – MightyPork

2

Me enfrentaba también a ese problema (expresiones dinámicas). Idid de esa manera, que podría no ser la mejor manera, pero funciona. En lugar de arrojar una Excepción, por supuesto puede devolver nulo o falso o lo que sea que desee. Espero que esto ayude.

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 cadena que contiene números y los operadores matemáticos + - */se pasa como entrada. El programa debe evaluar el valor de la expresión (según BODMAS) e imprimir la salida.

Ejemplo de entrada/salida: Si el argumento es "7 + 4 * 5", la salida debe ser 27. Si el argumento es "55 + 21 * 11 - 6/0", la salida debe ser "error" (Como la división por cero no está definida).

3

sólo tiene que configurar un controlador de errores para lanzar una excepción en caso de errores:

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

solución simple:

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

I He estado luchando con esto también, las soluciones set_error_handler no me funcionaban, probablemente basado en las diferencias de versión de PHP.

La solución para mí fue intentar detectar un error en el cierre:

// 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'); 

No estoy seguro de por qué una división por 0 se está cerrando en lugar de ser manejado por el set_error_handler pero esto me ayudó a conseguir Más allá de eso, muriendo silenciosamente.

1

En PHP7 puede utilizar DivisionByZeroError

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