PHP, как поймать деление на ноль?
у меня есть большие математическое выражение, которое должно быть создано динамически. Например, как только я проанализировал "что-то", результатом будет строка типа: "$foo+$bar/$baz";
.
Итак, для вычисления результата этого выражения я использую
eval("$result = $expresion;");
echo "The result is: $result";
проблема здесь в том, что иногда я получаю ошибки, которые говорят, что было деление на ноль, и я не знаю, как поймать это исключение. Я пробовал. например:
eval("try{$result = $expresion;}catch(Exception $e){$result = 0;}");
echo "The result is: $result";
или:
try{
eval("$result = $expresion;");
}
catch(Exception $e){
$result = 0;
}
echo "The result is: $result";
но это не работает. Итак, как я могу избежать сбоя моего приложения, когда есть деление на ноль?
Edit:
во-первых, я хочу кое-что прояснить: выражение построено динамически, поэтому я не могу просто оценить, если знаменатель равен нулю. Так... что касается комментария Марка Бейкера, позвольте привести вам пример. Мой парсер может построить что-то вроде это:
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
парсер строит строку шаг за шагом, не беспокоясь о значении vars... так что в этом случае, если $foz == $bak
на самом деле есть деление на ноль:$baz / ( 0 )
.
<?php
$a = 5;
$b = 0;
if(@eval(" try{ $res = $a/$b; } catch(Exception $e){}") === FALSE)
$res = 0;
echo "$resn";
?>
но он ничего не печатает.
12 ответов
if ($baz == 0.0) {
echo 'Divisor is 0';
} else {
...
}
вместо использования eval, что очень опасно, если вы используете пользовательский ввод в выражении evalled, почему бы не использовать правильный парсер, такой как evalmath на PHPClasses, и который вызывает чистое исключение при делении на ноль
вот еще одно решение:
<?php
function e($errno, $errstr, $errfile, $errline) {
print "caught!\n";
}
set_error_handler('e');
eval('echo 1/0;');
посмотреть set_error_handler()
вам просто нужно установить обработчик ошибок, чтобы бросить исключение в случае ошибки:
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.
поскольку этот совет кажется бесполезным для вашей цели, вот немного фона для обработки ошибок PHP.
в ранних версиях PHP не было исключений. Вместо этого были подняты сообщения об ошибках различных уровней (уведомления, предупреждения и т. д.). Неустранимая ошибка останавливает выполнение.
PHP5 привел исключения из таблицы и более новые библиотеки PHP (PDO) будет бросать исключения, когда происходят плохие / неожиданные вещи. Hoever, основная кодовая база не была переписана для использования exception. Основные функции и операции по-прежнему зависят от старой системы ошибок.
когда вы делите на 0, вы получаете предупреждение, а не исключение
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(@eval("$result = $expresion;")===FALSE){
$result=0;
}
не просто поймает деление на 0 ошибок, хотя.
Я также столкнулся с этой проблемой (динамические выражения). Idid это так, что может быть не самый хороший способ, но он работает. Вместо того, чтобы выбрасывать исключение, вы можете, конечно, вернуть null или false или что угодно. Надеюсь, это поможет.
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;
}
на PHP7 вы можете использовать DivisionByZeroError
try {
echo 1/0;
}
catch(DivisionByZeroError $e){
echo "got $e";
}
использовать @
(An оператор контроля ошибок.) Это говорит php не выводить предупреждения в случае ошибок.
eval("$result = @($expresion);");
if ($result == 0) {
// do division by zero handling
} else {
// it's all good
}
в качестве входных данных передается строка, содержащая числа и математические операторы+ -*/. Программа должна оценить значение выражения (согласно BODMAS) и распечатать выходные данные.
Пример Ввода/Вывода: Если аргумент "7 + 4*5" выход должен быть 27. Если аргумент "55 + 21 * 11 - 6/0" выход должен быть "ошибки" (как деление на нуль не определено).
Я тоже боролся с этим,set_error_handler
решения не работали для меня, вероятно, на основе различий в версиях PHP.
решение для меня было попытаться обнаружить ошибку при выключении:
// 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');
Я не уверен, почему деление на 0 закрывается, а не обрабатывается set_error_handler
но это помогло мне выйти за его пределы, просто тихо умирая.