Неожиданный результат в PHP сложен троичный оператор - PullRequest
0 голосов
/ 18 сентября 2018

Я использую PHP, чтобы попытаться получить процент, разделив одно число на другое. Однако, если любое из этих значений равно false, результатом по умолчанию должно быть 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 ]

0 голосов
/ 18 сентября 2018

Причина, по которой это не работает, заключается в том, что PHP обрабатывает ассоциативность троичных операторов иначе, чем вы могли бы ожидать.Из руководства :

// 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;

=>

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

=>

$countOne / $countTwo

следовательно вы получите ошибку деления на 0.Вам нужно вручную сгруппировать второго оператора, чтобы он работал правильно, т.е.

(! $countOne || ! $countTwo) ?
        0.0 :
            (($countOne > $countTwo) ?
                $countTwo / $countOne :
                    $countOne / $countTwo); 
0 голосов
/ 18 сентября 2018

Много лет назад создатель PHP допустил ошибку, которую сейчас слишком поздно исправлять, что привело к бесполезной «ассоциативности» троичного оператора, которая описана в примечании на странице руководства .

Рекомендуется избегать «укладки» троичных выражений.Поведение 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, поэтому существует риск запуска деления на ноль ошибок.

0 голосов
/ 18 сентября 2018

Это проблема приоритета оператора.

Конечно, я должен сказать, что это не очень чистый код. Тем не мение Попробуйте использовать скобки после точек с запятой в альтернативном варианте;

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