PHP, How to catch a division by zero? - php

I have a large mathematical expression that has to be created dynamically. For example, once I have parsed "something" the result will be a string like: "$foo+$bar/$baz";.
So, for calculating the result of that expression I'm using the eval function... something like this:
eval("\$result = $expresion;");
echo "The result is: $result";
The problem here is that sometimes I get errors that says there was a division by zero, and I don't know how to catch that Exception. I have tried things like:
eval("try{\$result = $expresion;}catch(Exception \$e){\$result = 0;}");
echo "The result is: $result";
Or:
try{
eval("\$result = $expresion;");
}
catch(Exception $e){
$result = 0;
}
echo "The result is: $result";
But it does not work. So, how can I avoid that my application crashes when there is a division by zero?
Edit:
First, I want to clarify something: the expression is built dynamically, so I can't just eval if the denominator is zero. So... with regards to the Mark Baker's comment, let me give you an example. My parser could build something like this:
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
The parser build the string step by step without worrying about the value of the vars... so in this case if $foz == $bak there's in fact a division by zero: $baz / ( 0 ).
On the other hand as Pete suggested, I tried:
<?php
$a = 5;
$b = 0;
if(#eval(" try{ \$res = $a/$b; } catch(Exception \$e){}") === FALSE)
$res = 0;
echo "$res\n";
?>
But it does not print anything.

On PHP7 you can use DivisionByZeroError
try {
echo 1/0;
} catch(DivisionByZeroError $e){
echo "got $e";
} catch(ErrorException $e) {
echo "got $e";
}

if ($baz == 0.0) {
echo 'Divisor is 0';
} else {
...
}
Rather than use eval, which is highly dangerous if you're using user-input within the evalled expression, why not use a proper parser such as evalmath on PHPClasses, and which raises a clean exception on divide by zero

You just need to set an error handler to throw an exception in case of errors:
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();

Here's another solution:
<?php
function e($errno, $errstr, $errfile, $errline) {
print "caught!\n";
}
set_error_handler('e');
eval('echo 1/0;');
See set_error_handler()

As others have mentioned, consider trying a solution that will let you check if the denominator is 0.
Since that advice seems useless your purpose, here's a little background on PHP error handling.
Early versions of PHP didn't have exceptions. Instead, error messages of various levels were raised (Notices, Warnings, Etc). A Fatal error stops execution.
PHP5 brought exceptions to the table, and newer PHP provided libraries (PDO) will throw exceptions when bad/unexpected things happen. Hoever, the core codebase was NOT rewritten to use exception. Core functions and operations still rely on the old error system.
When you divide by 0, you get a Warning, not an 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
If you want to "catch" these, you'll need to set a custom error handler that will detect division by zero errors and do something about them. Unfortunately, custom error handlers are a catch all, which means you'll also need to write some code to do something appropriate with all other errors.

if(#eval("\$result = $expresion;")===FALSE){
$result=0;
}
Won't just catch divide by 0 errors though.

I was facing that problem as well (dynamic expressions). Idid it that way which might not be the nicest way but it works. Instead of throwing an Exception you can of course return null or false or whatever you wish. Hope this helps.
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;
}

I've been struggling with this too, the set_error_handler solutions were not working for me, probably based on PHP version differences.
The solution for me was to attempt to detect an error on shutdown:
// 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');
I'm not sure why a divide by 0 is shutting down rather than being handled by the set_error_handler but this helped me get beyond it just silently dying.

If no additional handling is necessary you could also just do
$division = $foo / ($bar ?: 1);

Use a # (An error control operator.) This tells php to not output warnings in case of errors.
eval("\$result = #($expresion);");
if ($result == 0) {
// do division by zero handling
} else {
// it's all good
}

A string containing numbers and the mathematical operators + - * / is passed as input.
The program must evaluate the value of the expression (as per BODMAS) and print the output.
Example Input/Output:
If the argument is "7 + 4*5" the output must be 27.
If the argument is "55 + 21 * 11 - 6/0" the output must be "error" (As division by zero is not defined).

Problem:
b=1; c=0;
a=b/c;
// Error Divide by zero
Solution simple:
if(c!=0) a=b/c;
else // error handling

I realize this is an old question, but it is relevant today and I don't really like the answers here.
The proper way to fix this, is by actually evaluating the expression yourself - that is, by parsing the expression, then evaluating it step by step, instead of by transpiling it to PHP. This can be done using the https://en.wikipedia.org/wiki/Shunting-yard_algorithm.
I wrote the following implementation, but I haven't tested it. It's based on the above Wikipedia article. There is no support for right-associative operators, so it's slightly simplified.
// You may need to do a better parsing than this to tokenize your expression.
// In PHP, you could for example use token_get_all()
$formula = explode(' ', 'foo + bar * ( baz / ( foz - bak ) )');;
$queue = array();
$operators = array();
$precedence = array('-' => 2, '+' => 2, '/' => 3, '*' => 3, '^' => 4);
$rightAssoc = array('^');
$variables = array('foo' => $foo, 'bar' => $bar, 'baz' => $baz, 'foz' => $foz, 'bak' => $bak);
foreach($formula as $token) {
if(isset($variables[$token])) {
$queue[] = $variables[$token];
} else if(isset($precedence[$token])) {
// This is an operator
while(
sizeof($operators) > 0 &&
$operators[sizeof($operators)-1] != '(' && (
$precedence[$operators[sizeof($operators)-1]] > $precedence[$token] ||
(
$precedence[$operators[sizeof($operators)-1]] == $precedence[$token] &&
!in_array($operators[sizeof($operators)-1], $rightAssoc)
)
)
) $queue[] = array_pop($operators);
$operators[] = $token;
} else if($token == '(') {
$operators[] = '(';
} else if($token == ')') {
while($operators[sizeof($operators)-1] != '(') {
$queue[] = array_pop($operators);
}
array_pop($operators);
} else if($token == ')') {
while($operators[sizeof($operators)-1] != ')') {
$queue[] = array_pop($operators);
}
if(null === array_pop($operators))
throw new \Exception("Mismatched parentheses");
}
$queue = array_merge($queue, array_reverse($operators));
$stack = array();
foreach($queue as $token) {
if(is_numeric($token)) $stack[] = $token;
else switch($token) {
case '+' :
$stack[] = array_pop($stack) + array_pop($stack);
break;
case '-' :
// Popped variables come in reverse, so...
$stack[] = -array_pop($stack) + array_pop($stack);
break;
case '*' :
$stack[] = array_pop($stack) * array_pop($stack);
break;
case '/' :
$b = array_pop($stack);
$a = array_pop($stack);
if($b == 0)
throw new \Exception("Division by zero");
$stack[] = $a / $b;
break;
}
}
echo "The result from the calculation is ".array_pop($stack)."\n";
In your particular case
Even though I would prefer the Shunting Yard solution - if I still decided to go for an eval()-version, I would create a custom_division($leftHandSide, $rightHandSide) method, that throws an exception. This code:
eval("$foo + $bar * ( $baz / ( $foz - $bak ) )");
becomes
function custom_division($a, $b) { if($b == 0) throw Exception("Div by 0"); }
eval("$foo + $bar * ( custom_division( $baz, ( $foz - $bak ) )");

using intdiv and DivisionByZeroError:
try {
$a = 5;
$b = 0;
intdiv($a,$b);
}
catch(DivisionByZeroError $e){
echo "got {$e->getMessage()}";
}

This is the best way I found to accomplish this:
error_clear_last(); // Clear any previous error
$result = #(1/0); // Executes the division, suppressing the errors
$e = error_get_last(); // Catches the last error
if ($e !== null && $e['message'] == 'Division by zero') {
// Division by zero occurred, do something here
}

Related

Laravel Throwable not handle exception - get 500 internal error [duplicate]

I have a large mathematical expression that has to be created dynamically. For example, once I have parsed "something" the result will be a string like: "$foo+$bar/$baz";.
So, for calculating the result of that expression I'm using the eval function... something like this:
eval("\$result = $expresion;");
echo "The result is: $result";
The problem here is that sometimes I get errors that says there was a division by zero, and I don't know how to catch that Exception. I have tried things like:
eval("try{\$result = $expresion;}catch(Exception \$e){\$result = 0;}");
echo "The result is: $result";
Or:
try{
eval("\$result = $expresion;");
}
catch(Exception $e){
$result = 0;
}
echo "The result is: $result";
But it does not work. So, how can I avoid that my application crashes when there is a division by zero?
Edit:
First, I want to clarify something: the expression is built dynamically, so I can't just eval if the denominator is zero. So... with regards to the Mark Baker's comment, let me give you an example. My parser could build something like this:
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
The parser build the string step by step without worrying about the value of the vars... so in this case if $foz == $bak there's in fact a division by zero: $baz / ( 0 ).
On the other hand as Pete suggested, I tried:
<?php
$a = 5;
$b = 0;
if(#eval(" try{ \$res = $a/$b; } catch(Exception \$e){}") === FALSE)
$res = 0;
echo "$res\n";
?>
But it does not print anything.
On PHP7 you can use DivisionByZeroError
try {
echo 1/0;
} catch(DivisionByZeroError $e){
echo "got $e";
} catch(ErrorException $e) {
echo "got $e";
}
if ($baz == 0.0) {
echo 'Divisor is 0';
} else {
...
}
Rather than use eval, which is highly dangerous if you're using user-input within the evalled expression, why not use a proper parser such as evalmath on PHPClasses, and which raises a clean exception on divide by zero
You just need to set an error handler to throw an exception in case of errors:
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();
Here's another solution:
<?php
function e($errno, $errstr, $errfile, $errline) {
print "caught!\n";
}
set_error_handler('e');
eval('echo 1/0;');
See set_error_handler()
As others have mentioned, consider trying a solution that will let you check if the denominator is 0.
Since that advice seems useless your purpose, here's a little background on PHP error handling.
Early versions of PHP didn't have exceptions. Instead, error messages of various levels were raised (Notices, Warnings, Etc). A Fatal error stops execution.
PHP5 brought exceptions to the table, and newer PHP provided libraries (PDO) will throw exceptions when bad/unexpected things happen. Hoever, the core codebase was NOT rewritten to use exception. Core functions and operations still rely on the old error system.
When you divide by 0, you get a Warning, not an 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
If you want to "catch" these, you'll need to set a custom error handler that will detect division by zero errors and do something about them. Unfortunately, custom error handlers are a catch all, which means you'll also need to write some code to do something appropriate with all other errors.
if(#eval("\$result = $expresion;")===FALSE){
$result=0;
}
Won't just catch divide by 0 errors though.
I was facing that problem as well (dynamic expressions). Idid it that way which might not be the nicest way but it works. Instead of throwing an Exception you can of course return null or false or whatever you wish. Hope this helps.
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;
}
I've been struggling with this too, the set_error_handler solutions were not working for me, probably based on PHP version differences.
The solution for me was to attempt to detect an error on shutdown:
// 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');
I'm not sure why a divide by 0 is shutting down rather than being handled by the set_error_handler but this helped me get beyond it just silently dying.
If no additional handling is necessary you could also just do
$division = $foo / ($bar ?: 1);
Use a # (An error control operator.) This tells php to not output warnings in case of errors.
eval("\$result = #($expresion);");
if ($result == 0) {
// do division by zero handling
} else {
// it's all good
}
A string containing numbers and the mathematical operators + - * / is passed as input.
The program must evaluate the value of the expression (as per BODMAS) and print the output.
Example Input/Output:
If the argument is "7 + 4*5" the output must be 27.
If the argument is "55 + 21 * 11 - 6/0" the output must be "error" (As division by zero is not defined).
Problem:
b=1; c=0;
a=b/c;
// Error Divide by zero
Solution simple:
if(c!=0) a=b/c;
else // error handling
I realize this is an old question, but it is relevant today and I don't really like the answers here.
The proper way to fix this, is by actually evaluating the expression yourself - that is, by parsing the expression, then evaluating it step by step, instead of by transpiling it to PHP. This can be done using the https://en.wikipedia.org/wiki/Shunting-yard_algorithm.
I wrote the following implementation, but I haven't tested it. It's based on the above Wikipedia article. There is no support for right-associative operators, so it's slightly simplified.
// You may need to do a better parsing than this to tokenize your expression.
// In PHP, you could for example use token_get_all()
$formula = explode(' ', 'foo + bar * ( baz / ( foz - bak ) )');;
$queue = array();
$operators = array();
$precedence = array('-' => 2, '+' => 2, '/' => 3, '*' => 3, '^' => 4);
$rightAssoc = array('^');
$variables = array('foo' => $foo, 'bar' => $bar, 'baz' => $baz, 'foz' => $foz, 'bak' => $bak);
foreach($formula as $token) {
if(isset($variables[$token])) {
$queue[] = $variables[$token];
} else if(isset($precedence[$token])) {
// This is an operator
while(
sizeof($operators) > 0 &&
$operators[sizeof($operators)-1] != '(' && (
$precedence[$operators[sizeof($operators)-1]] > $precedence[$token] ||
(
$precedence[$operators[sizeof($operators)-1]] == $precedence[$token] &&
!in_array($operators[sizeof($operators)-1], $rightAssoc)
)
)
) $queue[] = array_pop($operators);
$operators[] = $token;
} else if($token == '(') {
$operators[] = '(';
} else if($token == ')') {
while($operators[sizeof($operators)-1] != '(') {
$queue[] = array_pop($operators);
}
array_pop($operators);
} else if($token == ')') {
while($operators[sizeof($operators)-1] != ')') {
$queue[] = array_pop($operators);
}
if(null === array_pop($operators))
throw new \Exception("Mismatched parentheses");
}
$queue = array_merge($queue, array_reverse($operators));
$stack = array();
foreach($queue as $token) {
if(is_numeric($token)) $stack[] = $token;
else switch($token) {
case '+' :
$stack[] = array_pop($stack) + array_pop($stack);
break;
case '-' :
// Popped variables come in reverse, so...
$stack[] = -array_pop($stack) + array_pop($stack);
break;
case '*' :
$stack[] = array_pop($stack) * array_pop($stack);
break;
case '/' :
$b = array_pop($stack);
$a = array_pop($stack);
if($b == 0)
throw new \Exception("Division by zero");
$stack[] = $a / $b;
break;
}
}
echo "The result from the calculation is ".array_pop($stack)."\n";
In your particular case
Even though I would prefer the Shunting Yard solution - if I still decided to go for an eval()-version, I would create a custom_division($leftHandSide, $rightHandSide) method, that throws an exception. This code:
eval("$foo + $bar * ( $baz / ( $foz - $bak ) )");
becomes
function custom_division($a, $b) { if($b == 0) throw Exception("Div by 0"); }
eval("$foo + $bar * ( custom_division( $baz, ( $foz - $bak ) )");
using intdiv and DivisionByZeroError:
try {
$a = 5;
$b = 0;
intdiv($a,$b);
}
catch(DivisionByZeroError $e){
echo "got {$e->getMessage()}";
}
This is the best way I found to accomplish this:
error_clear_last(); // Clear any previous error
$result = #(1/0); // Executes the division, suppressing the errors
$e = error_get_last(); // Catches the last error
if ($e !== null && $e['message'] == 'Division by zero') {
// Division by zero occurred, do something here
}

PHP Try catch issue [duplicate]

I have a large mathematical expression that has to be created dynamically. For example, once I have parsed "something" the result will be a string like: "$foo+$bar/$baz";.
So, for calculating the result of that expression I'm using the eval function... something like this:
eval("\$result = $expresion;");
echo "The result is: $result";
The problem here is that sometimes I get errors that says there was a division by zero, and I don't know how to catch that Exception. I have tried things like:
eval("try{\$result = $expresion;}catch(Exception \$e){\$result = 0;}");
echo "The result is: $result";
Or:
try{
eval("\$result = $expresion;");
}
catch(Exception $e){
$result = 0;
}
echo "The result is: $result";
But it does not work. So, how can I avoid that my application crashes when there is a division by zero?
Edit:
First, I want to clarify something: the expression is built dynamically, so I can't just eval if the denominator is zero. So... with regards to the Mark Baker's comment, let me give you an example. My parser could build something like this:
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
The parser build the string step by step without worrying about the value of the vars... so in this case if $foz == $bak there's in fact a division by zero: $baz / ( 0 ).
On the other hand as Pete suggested, I tried:
<?php
$a = 5;
$b = 0;
if(#eval(" try{ \$res = $a/$b; } catch(Exception \$e){}") === FALSE)
$res = 0;
echo "$res\n";
?>
But it does not print anything.
On PHP7 you can use DivisionByZeroError
try {
echo 1/0;
} catch(DivisionByZeroError $e){
echo "got $e";
} catch(ErrorException $e) {
echo "got $e";
}
if ($baz == 0.0) {
echo 'Divisor is 0';
} else {
...
}
Rather than use eval, which is highly dangerous if you're using user-input within the evalled expression, why not use a proper parser such as evalmath on PHPClasses, and which raises a clean exception on divide by zero
You just need to set an error handler to throw an exception in case of errors:
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();
Here's another solution:
<?php
function e($errno, $errstr, $errfile, $errline) {
print "caught!\n";
}
set_error_handler('e');
eval('echo 1/0;');
See set_error_handler()
As others have mentioned, consider trying a solution that will let you check if the denominator is 0.
Since that advice seems useless your purpose, here's a little background on PHP error handling.
Early versions of PHP didn't have exceptions. Instead, error messages of various levels were raised (Notices, Warnings, Etc). A Fatal error stops execution.
PHP5 brought exceptions to the table, and newer PHP provided libraries (PDO) will throw exceptions when bad/unexpected things happen. Hoever, the core codebase was NOT rewritten to use exception. Core functions and operations still rely on the old error system.
When you divide by 0, you get a Warning, not an 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
If you want to "catch" these, you'll need to set a custom error handler that will detect division by zero errors and do something about them. Unfortunately, custom error handlers are a catch all, which means you'll also need to write some code to do something appropriate with all other errors.
if(#eval("\$result = $expresion;")===FALSE){
$result=0;
}
Won't just catch divide by 0 errors though.
I was facing that problem as well (dynamic expressions). Idid it that way which might not be the nicest way but it works. Instead of throwing an Exception you can of course return null or false or whatever you wish. Hope this helps.
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;
}
I've been struggling with this too, the set_error_handler solutions were not working for me, probably based on PHP version differences.
The solution for me was to attempt to detect an error on shutdown:
// 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');
I'm not sure why a divide by 0 is shutting down rather than being handled by the set_error_handler but this helped me get beyond it just silently dying.
If no additional handling is necessary you could also just do
$division = $foo / ($bar ?: 1);
Use a # (An error control operator.) This tells php to not output warnings in case of errors.
eval("\$result = #($expresion);");
if ($result == 0) {
// do division by zero handling
} else {
// it's all good
}
A string containing numbers and the mathematical operators + - * / is passed as input.
The program must evaluate the value of the expression (as per BODMAS) and print the output.
Example Input/Output:
If the argument is "7 + 4*5" the output must be 27.
If the argument is "55 + 21 * 11 - 6/0" the output must be "error" (As division by zero is not defined).
Problem:
b=1; c=0;
a=b/c;
// Error Divide by zero
Solution simple:
if(c!=0) a=b/c;
else // error handling
I realize this is an old question, but it is relevant today and I don't really like the answers here.
The proper way to fix this, is by actually evaluating the expression yourself - that is, by parsing the expression, then evaluating it step by step, instead of by transpiling it to PHP. This can be done using the https://en.wikipedia.org/wiki/Shunting-yard_algorithm.
I wrote the following implementation, but I haven't tested it. It's based on the above Wikipedia article. There is no support for right-associative operators, so it's slightly simplified.
// You may need to do a better parsing than this to tokenize your expression.
// In PHP, you could for example use token_get_all()
$formula = explode(' ', 'foo + bar * ( baz / ( foz - bak ) )');;
$queue = array();
$operators = array();
$precedence = array('-' => 2, '+' => 2, '/' => 3, '*' => 3, '^' => 4);
$rightAssoc = array('^');
$variables = array('foo' => $foo, 'bar' => $bar, 'baz' => $baz, 'foz' => $foz, 'bak' => $bak);
foreach($formula as $token) {
if(isset($variables[$token])) {
$queue[] = $variables[$token];
} else if(isset($precedence[$token])) {
// This is an operator
while(
sizeof($operators) > 0 &&
$operators[sizeof($operators)-1] != '(' && (
$precedence[$operators[sizeof($operators)-1]] > $precedence[$token] ||
(
$precedence[$operators[sizeof($operators)-1]] == $precedence[$token] &&
!in_array($operators[sizeof($operators)-1], $rightAssoc)
)
)
) $queue[] = array_pop($operators);
$operators[] = $token;
} else if($token == '(') {
$operators[] = '(';
} else if($token == ')') {
while($operators[sizeof($operators)-1] != '(') {
$queue[] = array_pop($operators);
}
array_pop($operators);
} else if($token == ')') {
while($operators[sizeof($operators)-1] != ')') {
$queue[] = array_pop($operators);
}
if(null === array_pop($operators))
throw new \Exception("Mismatched parentheses");
}
$queue = array_merge($queue, array_reverse($operators));
$stack = array();
foreach($queue as $token) {
if(is_numeric($token)) $stack[] = $token;
else switch($token) {
case '+' :
$stack[] = array_pop($stack) + array_pop($stack);
break;
case '-' :
// Popped variables come in reverse, so...
$stack[] = -array_pop($stack) + array_pop($stack);
break;
case '*' :
$stack[] = array_pop($stack) * array_pop($stack);
break;
case '/' :
$b = array_pop($stack);
$a = array_pop($stack);
if($b == 0)
throw new \Exception("Division by zero");
$stack[] = $a / $b;
break;
}
}
echo "The result from the calculation is ".array_pop($stack)."\n";
In your particular case
Even though I would prefer the Shunting Yard solution - if I still decided to go for an eval()-version, I would create a custom_division($leftHandSide, $rightHandSide) method, that throws an exception. This code:
eval("$foo + $bar * ( $baz / ( $foz - $bak ) )");
becomes
function custom_division($a, $b) { if($b == 0) throw Exception("Div by 0"); }
eval("$foo + $bar * ( custom_division( $baz, ( $foz - $bak ) )");
using intdiv and DivisionByZeroError:
try {
$a = 5;
$b = 0;
intdiv($a,$b);
}
catch(DivisionByZeroError $e){
echo "got {$e->getMessage()}";
}
This is the best way I found to accomplish this:
error_clear_last(); // Clear any previous error
$result = #(1/0); // Executes the division, suppressing the errors
$e = error_get_last(); // Catches the last error
if ($e !== null && $e['message'] == 'Division by zero') {
// Division by zero occurred, do something here
}

Error handling for division by zero [duplicate]

I have a large mathematical expression that has to be created dynamically. For example, once I have parsed "something" the result will be a string like: "$foo+$bar/$baz";.
So, for calculating the result of that expression I'm using the eval function... something like this:
eval("\$result = $expresion;");
echo "The result is: $result";
The problem here is that sometimes I get errors that says there was a division by zero, and I don't know how to catch that Exception. I have tried things like:
eval("try{\$result = $expresion;}catch(Exception \$e){\$result = 0;}");
echo "The result is: $result";
Or:
try{
eval("\$result = $expresion;");
}
catch(Exception $e){
$result = 0;
}
echo "The result is: $result";
But it does not work. So, how can I avoid that my application crashes when there is a division by zero?
Edit:
First, I want to clarify something: the expression is built dynamically, so I can't just eval if the denominator is zero. So... with regards to the Mark Baker's comment, let me give you an example. My parser could build something like this:
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
The parser build the string step by step without worrying about the value of the vars... so in this case if $foz == $bak there's in fact a division by zero: $baz / ( 0 ).
On the other hand as Pete suggested, I tried:
<?php
$a = 5;
$b = 0;
if(#eval(" try{ \$res = $a/$b; } catch(Exception \$e){}") === FALSE)
$res = 0;
echo "$res\n";
?>
But it does not print anything.
On PHP7 you can use DivisionByZeroError
try {
echo 1/0;
} catch(DivisionByZeroError $e){
echo "got $e";
} catch(ErrorException $e) {
echo "got $e";
}
if ($baz == 0.0) {
echo 'Divisor is 0';
} else {
...
}
Rather than use eval, which is highly dangerous if you're using user-input within the evalled expression, why not use a proper parser such as evalmath on PHPClasses, and which raises a clean exception on divide by zero
You just need to set an error handler to throw an exception in case of errors:
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();
Here's another solution:
<?php
function e($errno, $errstr, $errfile, $errline) {
print "caught!\n";
}
set_error_handler('e');
eval('echo 1/0;');
See set_error_handler()
As others have mentioned, consider trying a solution that will let you check if the denominator is 0.
Since that advice seems useless your purpose, here's a little background on PHP error handling.
Early versions of PHP didn't have exceptions. Instead, error messages of various levels were raised (Notices, Warnings, Etc). A Fatal error stops execution.
PHP5 brought exceptions to the table, and newer PHP provided libraries (PDO) will throw exceptions when bad/unexpected things happen. Hoever, the core codebase was NOT rewritten to use exception. Core functions and operations still rely on the old error system.
When you divide by 0, you get a Warning, not an 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
If you want to "catch" these, you'll need to set a custom error handler that will detect division by zero errors and do something about them. Unfortunately, custom error handlers are a catch all, which means you'll also need to write some code to do something appropriate with all other errors.
if(#eval("\$result = $expresion;")===FALSE){
$result=0;
}
Won't just catch divide by 0 errors though.
I was facing that problem as well (dynamic expressions). Idid it that way which might not be the nicest way but it works. Instead of throwing an Exception you can of course return null or false or whatever you wish. Hope this helps.
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;
}
I've been struggling with this too, the set_error_handler solutions were not working for me, probably based on PHP version differences.
The solution for me was to attempt to detect an error on shutdown:
// 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');
I'm not sure why a divide by 0 is shutting down rather than being handled by the set_error_handler but this helped me get beyond it just silently dying.
If no additional handling is necessary you could also just do
$division = $foo / ($bar ?: 1);
Use a # (An error control operator.) This tells php to not output warnings in case of errors.
eval("\$result = #($expresion);");
if ($result == 0) {
// do division by zero handling
} else {
// it's all good
}
A string containing numbers and the mathematical operators + - * / is passed as input.
The program must evaluate the value of the expression (as per BODMAS) and print the output.
Example Input/Output:
If the argument is "7 + 4*5" the output must be 27.
If the argument is "55 + 21 * 11 - 6/0" the output must be "error" (As division by zero is not defined).
Problem:
b=1; c=0;
a=b/c;
// Error Divide by zero
Solution simple:
if(c!=0) a=b/c;
else // error handling
I realize this is an old question, but it is relevant today and I don't really like the answers here.
The proper way to fix this, is by actually evaluating the expression yourself - that is, by parsing the expression, then evaluating it step by step, instead of by transpiling it to PHP. This can be done using the https://en.wikipedia.org/wiki/Shunting-yard_algorithm.
I wrote the following implementation, but I haven't tested it. It's based on the above Wikipedia article. There is no support for right-associative operators, so it's slightly simplified.
// You may need to do a better parsing than this to tokenize your expression.
// In PHP, you could for example use token_get_all()
$formula = explode(' ', 'foo + bar * ( baz / ( foz - bak ) )');;
$queue = array();
$operators = array();
$precedence = array('-' => 2, '+' => 2, '/' => 3, '*' => 3, '^' => 4);
$rightAssoc = array('^');
$variables = array('foo' => $foo, 'bar' => $bar, 'baz' => $baz, 'foz' => $foz, 'bak' => $bak);
foreach($formula as $token) {
if(isset($variables[$token])) {
$queue[] = $variables[$token];
} else if(isset($precedence[$token])) {
// This is an operator
while(
sizeof($operators) > 0 &&
$operators[sizeof($operators)-1] != '(' && (
$precedence[$operators[sizeof($operators)-1]] > $precedence[$token] ||
(
$precedence[$operators[sizeof($operators)-1]] == $precedence[$token] &&
!in_array($operators[sizeof($operators)-1], $rightAssoc)
)
)
) $queue[] = array_pop($operators);
$operators[] = $token;
} else if($token == '(') {
$operators[] = '(';
} else if($token == ')') {
while($operators[sizeof($operators)-1] != '(') {
$queue[] = array_pop($operators);
}
array_pop($operators);
} else if($token == ')') {
while($operators[sizeof($operators)-1] != ')') {
$queue[] = array_pop($operators);
}
if(null === array_pop($operators))
throw new \Exception("Mismatched parentheses");
}
$queue = array_merge($queue, array_reverse($operators));
$stack = array();
foreach($queue as $token) {
if(is_numeric($token)) $stack[] = $token;
else switch($token) {
case '+' :
$stack[] = array_pop($stack) + array_pop($stack);
break;
case '-' :
// Popped variables come in reverse, so...
$stack[] = -array_pop($stack) + array_pop($stack);
break;
case '*' :
$stack[] = array_pop($stack) * array_pop($stack);
break;
case '/' :
$b = array_pop($stack);
$a = array_pop($stack);
if($b == 0)
throw new \Exception("Division by zero");
$stack[] = $a / $b;
break;
}
}
echo "The result from the calculation is ".array_pop($stack)."\n";
In your particular case
Even though I would prefer the Shunting Yard solution - if I still decided to go for an eval()-version, I would create a custom_division($leftHandSide, $rightHandSide) method, that throws an exception. This code:
eval("$foo + $bar * ( $baz / ( $foz - $bak ) )");
becomes
function custom_division($a, $b) { if($b == 0) throw Exception("Div by 0"); }
eval("$foo + $bar * ( custom_division( $baz, ( $foz - $bak ) )");
using intdiv and DivisionByZeroError:
try {
$a = 5;
$b = 0;
intdiv($a,$b);
}
catch(DivisionByZeroError $e){
echo "got {$e->getMessage()}";
}
This is the best way I found to accomplish this:
error_clear_last(); // Clear any previous error
$result = #(1/0); // Executes the division, suppressing the errors
$e = error_get_last(); // Catches the last error
if ($e !== null && $e['message'] == 'Division by zero') {
// Division by zero occurred, do something here
}

Division by zero, php

I have created this function that correctly displays the infinity symbol when trying to enter 0 into the Y text box. However I still get the division by zero error... here is my code.
here is the case for switch statment
case '/':
$prod = $x / $y;
break;
hh
//check for divide by 0
function check0($y)
{
if ($y == 0)
throw new Exception ($prod = "&#8734");
return FALSE;
}
try
{
check0($y);
$prod = $x /$y;
}catch(Exception $zero){
echo $zero->getMessage();
}
First: you are doing a division at the second line code (which can be devision by zero).
Second: no need to return false in your method since you are throwing an error.
Third: Why using an exception here and not just let you method return true of false and check on that before executing the devision.
Fourth: Why having a method if you only need to check on the value of $y. Calling the method or including an if-statement requires both just one line of code.
So, why can't it just be like:
case '/':
if($y > 0)
$prod = $x / $y;
break;
This is because you actually do the division near the top (in the case).
Your logic feels ... mmm well entangled.... Here have a look at this:
<?php
function divide($x, $y) {
if ( $y === 0 )
throw new Exception("Divide By Zero");
return $x/$y;
}
try {
$product = divide(3, 0);
}
catch(Exception $e) {
if ( $e->getMessage() == "Divide By Zero" )
$product = "&#8734";
else
$product = NULL;
}
print "Product is $product\n";
?>
You must call check0() before division. You should return FALSE if y == 0, TRUE otherwise.
If return TRUE then do division. However it's not necessary call a method to do this!
In my case everything works fine. Be sure, you are not trying to use division earlier in your script, because it look's like.
case '/':
$prod = $x / $y;
break;
starts before your function call.

How to catch this error: "Notice: Undefined offset: 0"

I want to catch this error:
$a[1] = 'jfksjfks';
try {
$b = $a[0];
} catch (\Exception $e) {
echo "jsdlkjflsjfkjl";
}
Edit: in fact, I got this error on the following line:
$parse = $xml->children[0]->children[0]->toArray();
You need to define your custom error handler like:
<?php
set_error_handler('exceptions_error_handler');
function exceptions_error_handler($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}
$a[1] = 'jfksjfks';
try {
$b = $a[0];
} catch (Exception $e) {
echo "jsdlkjflsjfkjl";
}
You can't with a try/catch block, as this is an error, not an exception.
Always tries offsets before using them:
if( isset( $a[ 0 ] ) { $b = $a[ 0 ]; }
I know it's 2016 but in case someone gets to this post.
You could use the array_key_exists($index, $array) method in order to avoid the exception to happen.
$index = 99999;
$array = [1,2,3,4,5,6];
if(!array_key_exists($index, $array))
{
//Throw myCustomException;
}
$a[1] = 'jfksjfks';
try {
$offset = 0;
if(isset($a[$offset]))
$b = $a[$offset];
else
throw new Exception("Notice: Undefined offset: ".$offset);
} catch (Exception $e) {
echo $e->getMessage();
}
Or, without the inefficiency of creating a very temporary exception:
$a[1] = 'jfksjfks';
$offset = 0;
if(isset($a[$offset]))
$b = $a[$offset];
else
echo "Notice: Undefined offset: ".$offset;
Important: Prefer not using this method, use others. While it works, it is ugly and has its own pitfalls, like falling into the trap of converting real and meaningful output into exceptions.
Normally, you can't catch notices with a simple try-catch block. But there's a hacky and ugly way to do it:
function convert_notice_to_exception($output)
{
if (($noticeStartPoint = \strpos($output, "<b>Notice</b>:")) !== false) {
$position = $noticeStartPoint;
for ($i = 0; $i < 3; $i++)
$position = strpos($output, "</b>", $position) + 1;
$noticeEndPoint = $position;
$noticeLength = $noticeEndPoint + 3 - $noticeStartPoint;
$noticeMessage = \substr($output, $noticeStartPoint, $noticeLength);
throw new \Exception($noticeMessage);
} else
echo $output;
}
try {
ob_start();
// Codes here
$codeOutput = ob_get_clean();
convert_notice_to_exception($codeOutput);
} catch (\Exception $exception) {
}
Also, you can use this function for to catch warnings. Just change function name to convert_warning_to_exception and change "<b>Notice</b>:" to "<b>Warning</b>:".
Note: The function will catch normal output that contains:
<b>Notice</b>:
To escape from this problem, simply, change it to:
<b>Notice:</b>
For the people who are getting the error
PHP Notice: unserialize(): Error at offset 191 of 285 bytes in ...
and are getting the data from a database, Make sure that you have the database set the the correct encoding, I had the database set as latin1_swedish_ci and all of the data looked perfect, Infact when i copied it into a online unserialize it worked fine. I changed the collation to utf8mb4_unicode_ci and all worked fine.
Source User Contributed Notes: https://www.php.net/manual/pt_BR/function.unserialize.php
I tried to utf8_decode before unserialize, and it's works fine.
Im sure why the Error Throw but i fix some..
in html2pdf.class.php
on Lines 2132:
//FIX:
$ctop=$corr[$y][$x][2]<=count($sw)?$corr[$y][$x][2]:count($sw);
$s = 0; for ($i=0; $i<$ctop; $i++) {$s+= array_key_exists($x+$i, $sw)? $sw[$x+$i]:0;}
SAME On line 2138:
//FIX:
$ctop=$corr[$y][$x][2]<=count($sw)?$corr[$y][$x][2]:count($sw);
for ($i=0; $i<$ctop; $i++) {
the problem the array $sw not have a key of $corr[$y][$x][2] so i fix the loop for to max count($sw) to fix ..
I dont know if that create an another consecuense but i resolve my problem y dont have any more errors..
So i hope works to you ..!!!
Beats Reguards

Categories