前几天我上课,并提供了这段代码:
<?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&gt; = 70等等 - 无论得分如何,每次都在整个筹码堆中工作。
对我来说,似乎这个构造应遵循给予数学运算符的相同优先顺序 - 首先解析最内层的括号,然后解决,除非三元运算有一些独特的运算顺序。
不幸的是,当我真正想了解它是如何工作的时候,课堂上的讨论很快就会成为争论的焦点。所以我的问题是两个:
(1)我如何解释这句话以及为什么?
和
(2)是否有某种堆栈跟踪或单步工具可以让我看到这段代码是如何执行的?
答案 0 :(得分:2)
PHP尊重括号。首先评估最内层( ... )
内的表达式,就像我们在小学教的那样。
PHP是不寻常的,因为三元运算符是left-associative。这意味着没有括号,三元表达式从左到右进行评估。
但在这种特殊情况下,括号强制表达式从右到左进行计算。此代码等同于:
if ($score >= 90) {
$grade = 'A';
}
elseif ($score >= 80) {
$grade = 'B';
}
elseif ($score >= 70) {
$grade = 'C';
}
...
答案 1 :(得分:1)
三元运算符短路。仅评估适当的操作数。这意味着在实际测试之前,它们并不重要。
echo false ? (crash() / 0) : "Worked.";
答案 2 :(得分:1)
三元从左到右:
http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary
所以它会评估左边的是什么?并在此基础上,评估:1的第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')));
答案 3 :(得分:1)
三元运算符是左关联的,但是应用了括号,它从右到左进行计算。
您可以使用xdebug
或phpdbg
作为步调试器来逐步执行代码并查看其评估方式。
还有VulcanLogicDumper,它显示了说明:
http://3v4l.org/QeF9i/vld#tabs 与if-elseif-else结构相比 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,以便了解它的评估方式:
感兴趣的是第5行,操作码编号5:
5 > JMPZ ~2, ->8
这意味着:如果与90(操作码4)比较为假,则JUMP为操作码8。
警告:->8
并不意味着跳转到第8行。
现在,Opcode 8是什么?与80的比较
6 8 > IS_SMALLER_OR_EQUAL ~4 80, !0
现在可以肯定地说,这不会像你从内到外(90-> 60-> 70)那样进行评估,而是像if-elseif-else结构一样(90-> 80-大于70)
。