代码之家  ›  专栏  ›  技术社区  ›  dewd

php堆栈三元运算符中出现意外结果

  •  1
  • dewd  · 技术社区  · 6 年前

    我正在使用php尝试用一个数字除以另一个数字来得到一个百分比。但是,如果其中一个数字是错误的,则默认结果应为0.0。我正在使用三元运算来确定结果。然而,它似乎是默认的最后一个计算,这显然等于一个除以零的错误。有什么想法吗?

    代码:

    $countOne = 3;
    $countTwo = 0;
    echo (! $countOne || ! $countTwo) ? 'true' : 'false';
    
    $number =
        (! $countOne || ! $countTwo) ?
            0.0 :
                ($countOne > $countTwo) ?
                    $countTwo / $countOne :
                        $countOne / $countTwo;
    
    echo $number;
    

    现在我将使用if语句,但我不明白为什么上面的语句不起作用。

    测试: http://sandbox.onlinephpfunctions.com/code/83f737ab27fb046a8eb9feb4992d5dd26340723d

    3 回复  |  直到 6 年前
        1
  •  3
  •   IMSoP    6 年前

    许多年前,PHP的创建者犯了一个错误,现在已经太晚了,无法修复,导致三元运算符的“关联性”毫无帮助,这在 the manual page .

    建议避免“堆叠”三元表达式。在一条语句中使用多个三元运算符时,PHP的行为并不明显:

    …这是因为三元表达式是从左到右进行计算的

    所以当你写这篇文章时:

    $number =
        (! $countOne || ! $countTwo) ?
            0.0 :
                ($countOne > $countTwo) ?
                    $countTwo / $countOne :
                        $countOne / $countTwo;
    

    您希望PHP将其理解为:

    $number =
        (
            (! $countOne || ! $countTwo) 
                ? 0.0
                : (
                    ($countOne > $countTwo)
                        ? $countTwo / $countOne
                        : $countOne / $countTwo
                   )
        );
    

    也就是说,执行第一个测试,然后给出最终结果 0.0 或继续进行第二次测试。

    但PHP实际上理解为:

    $number =
        (
            (! $countOne || ! $countTwo) 
                ? 0.0
                : ($countOne > $countTwo)
        )
        ? $countTwo / $countOne
        : $countOne / $countTwo;
    

    换言之,整体第一 ... ? ... : ... 首先计算表达式,当第二个表达式运行时,它将使用以下三种可能性之一:

     $number = 0.0 ? $countTwo / $countOne : $countOne / $countTwo;
     $number = true ? $countTwo / $countOne : $countOne / $countTwo;
     $number = false ? $countTwo / $countOne : $countOne / $countTwo;
    

    所有这些都将评估 $countTwo / $countOne $countOne / $countTwo 因此有可能引发零误差除法。

        2
  •  2
  •   staskrak    6 年前

    这是一个运算符优先级问题。

    当然,我应该说这不是一个非常干净的代码。无论如何 在备选方案中,尽量使用分号后的括号;

    $number =
        (!$countOne || !$countTwo) ?
            0.0 :
                (($countOne > $countTwo) ?
                    $countTwo / $countOne :
                        $countOne / $countTwo);
    
        3
  •  2
  •   Nick SamSmith1986    6 年前

    它不起作用的原因是PHP处理三元运算符关联性的方式与您预期的不同。从 manual :

    // ternary operator associativity differs from C/C++
    $a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2
    

    因此,您的表达式计算为

    ((! $countOne || ! $countTwo) ? 0.0 : ($countOne > $countTwo)) ?
       $countTwo / $countOne : $countOne / $countTwo;
    

    = & gt;

    0.0 ? $countTwo / $countOne : $countOne / $countTwo;
    

    = & gt;

    $countOne / $countTwo
    

    因此得到除以0的误差。您需要手动将第二个操作员分组,使其正常工作,即

    (! $countOne || ! $countTwo) ?
            0.0 :
                (($countOne > $countTwo) ?
                    $countTwo / $countOne :
                        $countOne / $countTwo);