2014-09-09 6 views
0

я был в классе, на другой день, и этот фрагмент кода:Порядок старшинства с вложенными трехкомпонентных операторами

<?php 
//Intialize the input 
$score=rand(50,100); 
//Determine the Grade 
$grade=($score>=90)?'A':(
($score>=80)?'B':(
($score>=70)?'C':(
($score>=60)?'D':'F'))); 
//Output the Results 
echo "<h1>A score of $score = $grade</h1>"; 
?> 

В то время я поставил под сомнение порядок операций в рамках вложенных тройных операторов, полагая, что они будет оценивать изнутри, то есть он будет оценивать, если бы $ score был> = 60 сначала, тогда, если $ score> = 70 и т. д. - каждый день обрабатывать весь стек независимо от оценки.

Для меня кажется, что эта конструкция должна следовать тому же порядку приоритета, который задается математическим операторам, сначала разрешая внутреннее множество скобок, а затем разрабатывая, если только не существует порядка операций, уникальных для троичного.

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

(1) Как бы это заявление меня интерпретировало и почему?

и

(2) Является ли какой-то трассировки стека или пошагово инструмент, который позволил бы мне посмотреть, как этот код выполняет?

+0

Это тривиально легко проверить для себя. – meagar

+0

Только тривиально для тех, кто знает, как – SeanOlson

ответ

2

PHP уважает скобки, то есть выражения внутри самого внутреннего (...) оцениваются сначала, как нас учат в начальной школе. При этом PHP необычен в том, что троичные операторы: left-associative. Это означает, что без скобок тернарное выражение оценивается слева направо.

Но в этом конкретном случае скобки заставляют выражение оцениваться справа налево. Этот код эквивалентен:

if ($score >= 90) { 
    $grade = 'A'; 
} 
elseif ($score >= 80) { 
    $grade = 'B'; 
} 
elseif ($score >= 70) { 
    $grade = 'C'; 
} 
... 
+0

Огромное спасибо за объяснение и ссылку. – SeanOlson

1

Тернарный оператор короткого замыкания. Оценивается только соответствующий операнд. Это означает, что parens не имеют значения, пока они не будут фактически протестированы.

echo false ? (crash()/0) : "Worked."; 
+0

Спасибо за рекомендацию отладки, Ignacio – SeanOlson

1

тройная являются слева направо:

http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary

Так будет оценивать то, что это слева от? и, основываясь на этом, оцените либо 1-ю, либо 2-ю сторону:.

Вы можете поместить в вызове функции, которая имеет побочный эффект, чтобы продемонстрировать это:

function p($a,$b) { echo $a . " >= " . $b; return $a>=$b; } 
$grade=(p($score,90))?'A':(
p($score,80)?'B':(
p($score,70)?'C':(
p($score,60)?'D':'F'))); 
+0

Спасибо, что ответили, но согласно Робу и его ссылке тройной фактически справа налево, когда он анализирует заявление слева от вопросительного знака. Мне нравится идея вставить вызов функции в тройной, чтобы заставить его отчитываться. Я не понимал, что ты можешь так поступить. Приветствия. – SeanOlson

1

Тройной оператор левоассоциативна, но применяются скобки, оно вычисляется справа налево.

В качестве шага отладчика вы можете использовать xdebug или phpdbg, чтобы просмотреть свой код и посмотреть, как он оценивается.

Существует также VulcanLogicDumper вокруг, который показывает инструкции:

http://3v4l.org/QeF9i/vld#tabs по сравнению с if-ElseIf-иначе структура http://3v4l.org/bZE6M/vld#tabs

line  # * op       fetch   ext return operands 
--------------------------------------------------------------------------------- 
    3  0 > SEND_VAL             50 
     1  SEND_VAL             100 
     2  DO_FCALL          2 $0  'rand' 
     3  ASSIGN             !0, $0 
    5  4  IS_SMALLER_OR_EQUAL        ~2  90, !0 
     5 > JMPZ              ~2, ->8 
     6 > QM_ASSIGN          ~3  'A' 
     7 > JMP              ->24 
    6  8 > IS_SMALLER_OR_EQUAL        ~4  80, !0 
     9 > JMPZ              ~4, ->12 
     10 > QM_ASSIGN          ~5  'B' 
     11 > JMP              ->23 
    7 12 > IS_SMALLER_OR_EQUAL        ~6  70, !0 
     13 > JMPZ              ~6, ->16 
     14 > QM_ASSIGN          ~7  'C' 
     15 > JMP              ->22 
    8 16 > IS_SMALLER_OR_EQUAL        ~8  60, !0 
     17 > JMPZ              ~8, ->20 
     18 > QM_ASSIGN          ~9  'D' 
     19 > JMP              ->21 
     20 > QM_ASSIGN          ~9  'F' 
     21 > QM_ASSIGN          ~7  ~9 
     22 > QM_ASSIGN          ~5  ~7 
     23 > QM_ASSIGN          ~3  ~5 
     24 > ASSIGN             !1, ~3 
    10 25  ADD_STRING          ~11  '%3Ch1%3EA+score+of+' 
     26  ADD_VAR           ~11  ~11, !0 
     27  ADD_STRING          ~11  ~11, '+%3D+' 
     28  ADD_VAR           ~11  ~11, !1 
     29  ADD_STRING          ~11  ~11, '%3C%2Fh1%3E' 
     30  ECHO              ~11 
     31 > RETURN             1 

How to read these Opcodes

Я буду попробуйте объяснить первый JMPZ в o PCODE для того, чтобы понять, как он оценивает:

Интересна линия 5, Опкод Номер 5:

5 > JMPZ ~2, ->8

Это означает: Если сравнивать с 90 (опкодом 4) является ложным, затем прыгайте Опкод 8.

Внимание: ->8 не означает, что переход к линии 8.

Теперь, что Опкод 8? Сравнение с 80

6 8 > IS_SMALLER_OR_EQUAL ~4 80, !0

И теперь можно с уверенностью сказать, что это не оценивает, как вы ожидали от наизнанку (90-> 60-> 70), но, как Условный ElseIf-то еще структура (90-> 80-> 70).

+0

Спасибо, Дженс-Андре. Я тщетно пытался заставить xdebug работать на NetBeans. Теперь я перешел к SublimeText2 по многим причинам. Какую IDE вы используете для подготовки отчета? Ура! – SeanOlson

+0

Отчет, показанный здесь, не создается с помощью IDE, он создается по адресу http://3v4l.org/ - Tab «VCD opcodes». Если вы хотите сделать это на своей собственной машине, вы можете попробовать расширение VLD: http://pecl.php.net/package/vld. Есть много учебных пособий, объясняющих, как жениться на xdebug с Netbeans. Возможно, это поможет: https://www.youtube.com/watch?v=HbJOP0YcSjs –

+0

Прохладный - спасибо. Я потрачу некоторое время с этим позже. – SeanOlson

Смежные вопросы