У меня есть большое математическое выражение, которое должно создаваться динамически. Например, как только я проанализировал «что-то», результатом будет строка типа "$foo+$bar/$baz";
,
Итак, для вычисления результата этого выражения я использую функцию eval
… что-то вроде этого:
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";
Но это не работает. Итак, как я могу избежать того, что мое приложение сработает, когда есть деление на ноль?
Редактировать:
Во-первых, я хочу кое-что прояснить: выражение построено динамически, поэтому я не могу просто оценить, если знаменатель равен нулю. Итак … что касается комментария Марка Бейкера, позвольте мне привести вам пример. Мой анализатор мог бы построить что-то вроде этого:
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
Парсер строит строку шаг за шагом, не беспокоясь о значении варов … так что в этом случае, если $foz == $bak
есть деление на ноль: $baz / ( 0 )
.
С другой стороны, как предложил Пит, я попытался:
<?php $a = 5; $b = 0; if(@eval(" try{ \$res = $a/$b; } catch(Exception \$e){}") === FALSE) $res = 0; echo "$res\n"; ?>
Но ничего не печатает.
if ($baz == 0.0) { echo 'Divisor is 0'; } else { ... }
Вместо использования eval, который очень опасен, если вы используете пользовательский ввод в выраженном выражении, почему бы не использовать правильный парсер, такой как evalmath на PHPClasses , и который вызывает чистое исключение при делении на ноль
Вот еще одно решение:
<?php function e($errno, $errstr, $errfile, $errline) { print "caught!\n"; } set_error_handler('e'); eval('echo 1/0;');
См. set_error_handler()
Как уже упоминалось, рассмотрите попытку решения, которое позволит вам проверить, равен ли знаменатель 0.
Поскольку этот совет кажется бесполезным для вашей цели, вот небольшой справочник по обработке ошибок PHP.
Ранние версии PHP не имели исключений. Вместо этого сообщения об ошибках различных уровней были подняты (уведомления, предупреждения и т. Д.). Неустранимая ошибка прекращает выполнение.
PHP5 привел исключения из таблицы, а новые библиотеки, предоставляемые PHP (PDO), будут генерировать исключения, когда происходят плохие / неожиданные события. Ховер, основная кодовая база НЕ была переписана для использования исключения. Основные функции и операции по-прежнему зависят от старой системы ошибок.
Когда вы делите на 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
Если вы хотите «поймать» их, вам нужно будет настроить собственный обработчик ошибок, который будет обнаруживать деление на нулевые ошибки и что-то делать с ними. К сожалению, пользовательские обработчики ошибок – это уловка, а это значит, что вам также потребуется написать код, чтобы сделать что-то подходящее для всех других ошибок.
Вам просто нужно установить обработчик ошибок для исключения исключения в случае ошибок:
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();
if(@eval("\$result = $expresion;")===FALSE){ $result=0; }
Однако не поймать деление на 0 ошибок.
Я столкнулся с этой проблемой (динамические выражения). Идите так, что может быть не самым приятным способом, но он работает. Вместо того, чтобы бросать исключение, вы можете, конечно, вернуть нуль или ложь или что угодно. Надеюсь это поможет.
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"; }
Используйте @
( оператор управления ошибкой .) Это говорит, что 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», выход должен быть «ошибкой» (поскольку деление на ноль не определен).
Проблема:
b=1; c=0; a=b/c; // Error Divide by zero
Решение простое:
if(c!=0) a=b/c; else // error handling
Я тоже set_error_handler
решения 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
но это помогло мне выйти за пределы этого, просто молча умер.
Вы можете просто поймать DivisionByZeroError
в PHP> = 7