Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/233.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP,如何捕捉零除法?_Php_Exception_Divide By Zero - Fatal编程技术网

PHP,如何捕捉零除法?

PHP,如何捕捉零除法?,php,exception,divide-by-zero,Php,Exception,Divide By Zero,我有一个大的数学表达式,必须动态创建。例如,一旦我解析了“something”,结果将是如下字符串:“$foo+$bar/$baz” 所以,为了计算这个表达式的结果,我使用了eval函数。。。大概是这样的: eval("\$result = $expresion;"); echo "The result is: $result"; "$foo + $bar * ( $baz / ( $foz - $bak ) )" 这里的问题是,有时我会出现错误,表示存在被零除的情况,我不知道如何捕捉该异常

我有一个大的数学表达式,必须动态创建。例如,一旦我解析了“something”,结果将是如下字符串:
“$foo+$bar/$baz”

所以,为了计算这个表达式的结果,我使用了
eval
函数。。。大概是这样的:

eval("\$result = $expresion;");
echo "The result is: $result";
"$foo + $bar * ( $baz / ( $foz - $bak ) )"
这里的问题是,有时我会出现错误,表示存在被零除的情况,我不知道如何捕捉该异常。我尝试过以下方法:

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

但它不起作用。那么,当除法为零时,如何避免应用程序崩溃呢

编辑:

首先,我想澄清一点:表达式是动态构建的,所以如果分母为零,我不能仅求值。所以关于马克·贝克的评论,让我给你举个例子。我的解析器可以构建如下内容:

eval("\$result = $expresion;");
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(如果在evalled表达式中使用用户输入,这是非常危险的),为什么不使用适当的解析器,例如,并在除以零时引发干净的异常

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

但不会只捕获被0除的错误。

还有另一个解决方案:

<?php

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

set_error_handler('e');

eval('echo 1/0;');
使用
@
(An.)这告诉php在出现错误时不要输出警告

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

正如其他人所提到的,考虑一个可以让你检查分母是0的解决方案。< /P> 由于这个建议似乎对你的目的毫无用处,这里有一些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

如果你想“捕捉”这些错误,你需要检测出被零除的错误,并对它们采取措施。不幸的是,自定义错误处理程序是一个包罗万象的问题,这意味着您还需要编写一些代码来处理所有其他错误。

我也面临着这个问题(动态表达式)。我认为这可能不是最好的方法,但它确实有效。当然,您可以返回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;
}

包含数字和数学运算符+-*/的字符串作为输入传递。 程序必须计算表达式的值(根据BODMAS)并打印输出

输入/输出示例: 如果参数为“7+4*5”,则输出必须为27。
如果参数为“55+21*11-6/0”,则输出必须为“error”(因为未定义零除)。

您只需设置一个错误处理程序,以便在出现错误时引发异常:

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();
问题:

b=1;c=0;
a=b/c;
//错误除以零

解决方案简单:

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

我也一直在努力解决这个问题,
set\u error\u 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会被关闭,而不是被
设置错误处理程序处理,但这帮助我超越了它,只是静静地死去。

在PHP7上,你可以使用


我意识到这是一个老问题,但它与今天相关,我不太喜欢这里的答案

解决这个问题的正确方法是亲自计算表达式——也就是说,解析表达式,然后逐步计算,而不是将其传输到PHP。这可以使用

我编写了以下实现,但尚未对其进行测试。它基于上面维基百科的文章。不支持右关联运算符,因此稍微简化了

// 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";
在您的特定情况下

尽管我更喜欢调车场解决方案——如果我仍然决定使用eval()——版本,我会创建一个自定义的_division($leftHandSide,$rightHandSide)方法,该方法会抛出一个异常。此代码:

eval("$foo + $bar * ( $baz / ( $foz - $bak ) )");
变成

function custom_division($a, $b) { if($b == 0) throw Exception("Div by 0"); }
eval("$foo + $bar * ( custom_division( $baz, ( $foz - $bak ) )");

使用
intdiv
DivisionByZeroError

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

这是我找到的实现这一目标的最佳方法:

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
}

你能事先检查一下
$expression
是否被零除吗?@Anthony Forloney:好问题,我的回答假设你可以,但如果克里斯蒂安真的在使用eval,那么答案可能是“否”。使用
eval
可能是个坏主意。现在,您将允许最终用户在服务器上执行PHP代码。我不知道有没有其他选择,所以我不会发布答案,但是你应该考虑一下,你是否希望我能够输入任何PHP代码,不管它对你的网页有多大的破坏性。你能不能先使用eval测试分母是否为零,然后只在分母不为零的情况下计算原始表达式?编写一个语法分析器,对这些PHP代码公式进行标记,并通过你自己的;)token_get_all()将有帮助否。。。正如我所说,这个表达是建立在友好的基础上的。如果它是一个静态表达式,它将非常容易,但它不是。它是如何动态构建的?它必须由您的“解析器”以某种方式“构造”。。。在这一点上,你应该能够识别除数是否为0!如果您用eval(\$result=$baz;)替换$baz,然后test is$result为0或不为0,这应该可以使用。@标记我已经用回答您问题的更多信息更新了帖子