PHP中or运算符的行为

48
我试图理解or操作符的行为。请参考以下示例:
$e = false || true;
var_dump($e);

输出结果符合预期:bool(true);

$f = false or true;
var_dump($f);

输出结果符合预期:bool(false)。我的理解是 = 操作符比 Or 操作符的优先级高,所以 $f 被赋值为 false

但下面的代码与我想象的正好相反。我认为 $foo 会被赋值为 5 然后与自身进行比较。 但实际上只有在 $foo 已经被设置(也就是检查 $foo 是否已经被赋值),才会将其赋值为 5。

$foo or $foo = 5; 

有人能解释一下这为什么这样吗?


6
+1 很好的问题。对于那些在这个点上遇到困难的未来程序员非常有用。请问您需要帮助吗? - Lucas
1
与此不直接相关,您可能会发现这个页面有用:http://codeboutique.com/tools/pvaat/pvaat.php。我也考虑添加布尔运算符。 - Michael
我已经更新了页面,以显示不同情况下的“或”和“与”。有一些奇怪的结果。 - Michael
4个回答

49
基础知识:
  1. An assignment expression results in the assigned value.

    What does that mean? $foo = 'bar' is an expression, in which the assignment operator = assigns a value. An expression always returns a value itself. Just like the expression 1 + 2 results in the value 3, the expression $foo = 'bar' results in the value 'bar'. That's why this works:

    $foo = $bar = 'baz'; // which is: $foo = ($bar = 'baz');
    
  2. Boolean operations are short-circuiting operations. Both sides are not always evaluated if they don't need to be. true || false is always true overall, since the lefthand operand is true, so the whole expression must be true. false is not even being evaluated here.

  3. Operator precedence dictates in which order parts of an expression are grouped into sub-expressions. Higher precedence operators are grouped with their operands before lower precedence operators.

因此:
$e = false || true;
正在评估 false || true,结果为 true,并将其赋值给$e。运算符||的优先级高于=,因此false || true被分组为一个表达式(而不是($e = false) || true)。
$f = false or true;

现在,or的优先级比=低,这意味着在or之前,赋值操作被分组为一个表达式。因此,首先评估$f=false表达式,其结果是false(如上所述)。然后你有简单的表达式false or true,下一个要评估的表达式,结果为true,但没人关心它。

评估过程如下:

1. $f = false or true;
2. ($f = false) or true;  // precedence grouping
3. false or true;         // evaluation of left side ($f is now false)
4. true;                  // result

现在:

$foo or $foo = 5; 

在这里,$foo = 5 具有更高的优先级,被视为一个表达式。由于它出现在 or 运算符的右侧,只有在必要时才会对表达式进行求值。这取决于 $foo 最初的值。如果 $footrue,右侧将根本不会被评估,因为 true or ($foo = 5) 必须总体上是 true。但如果 $foo 最初的值为假值,则会评估右侧并将 5 分配给 $foo,结果为 5,它是真值,这意味着整个表达式是 true,但没人关心。

1. $foo or $foo = 5;
2. $foo or ($foo = 5);   // precedence grouping
3. false or ($foo = 5);  // evaluation of left side
4. false or 5;           // evaluation of right side ($foo is now 5)
5. true;                 // result

第一次就搞定了。感谢您如此好的解释。顺便说一下,我最近从您的“字符集”主题中受益匪浅。谢谢。 - Daric
看起来,当PHP不受or等短路运算符的限制时,它会先计算括号表达式,例如$foo = 2; echo $foo + ($foo = 4)将打印8而不是6。这是否实际上是语言规范的一部分,还是仅仅是一种实现决策? - Barmar
@Barbar 我相信你可以想出评估逻辑,但我认为这种自修改和大多无意义的操作的行为在定义上大多是未定义的。 - deceze
@Barmar 据我所知,这并没有被记录下来,但这主要不是因为括号的原因,而是因为对于一个表达式A + B,PHP首先评估A和B,然后将它们相加。现在来谈一下棘手的部分:$foo评估为相应的ZVal(变量引用),而($foo = 4)评估为具有修改$foo副作用的 4。 然后它们被加起来。 - Fabian Schmengler
请问什么情况下应该使用 $b 或者 $b = '1'; 呢?因为如果 $b 没有被设置,那么就会报错 Undefined variable error - NullPoiиteя

20

根据php.net有关逻辑运算符的页面

这个:

$e = false || true;

这样运作:

$e = (false || true) // If false is true, then $e = false. Otherwise true

这个:

$f = false or true;

会像这样:

($f = false) or true; // $f = false is true, as the assignment succeeded

这个:

$foo or $foo = 5; 

将会这样:

$foo or ($foo = 5) // foo = undefined or foo = 5, so foo = 5

最后一个问题中,undefined 基本上就像 false 一样,因此 foo 的值等于 5。

此外,以下是操作符优先级顺序的链接:http://www.php.net/manual/en/language.operators.precedence.php

更新:

好的,现在让我们来谈谈主要问题。就像我们都知道使用获取的查询时:

while($row = @mysql_fetch_assoc($result))

我们都知道while循环只在true的情况下执行,因此$row = @mysql_fetch_assoc($result)返回true。

Daric的问题也是一样。

$foo or $foo = 5;

基本上是:

$foo or ($foo = 5);

基本上是这样:

$foo = undefined or ($foo = 5); // $foo = 5 actually returns true

这也是

$foo = undefined or true;

正如我之前提到的,undefined = false,因此$foo = 5(因为这是正确的语句)。

希望大家都能理解。


如果$f无法被赋值,则为真 - 不,更确切地说是如果表达式$f = false的结果为true或者...。而赋值表达式的结果是被赋的值。 - deceze
@deceze 我认为不是这样的。这是根据PHP文档所述。 - Lucas
3
PHP文档确实指出赋值表达式“返回”所赋的结果 http://www.php.net/manual/en/language.operators.assignment.php 。这并不是“大致相同”,因为$f=true or false不会“执行”false,而$f=false or true将“执行”true - Passerby
1
@think123:在这个语句中$foo or $foo = 5;,为什么不先将5赋值给$foo,因为=的优先级高于or。为什么不先计算= - Daric
@ShaquinTrifonoff 这只是为了测试目的,不是严格用途。 - Lucas
显示剩余8条评论

3
$foo or $foo = 5;

Suppose let say $foo=true or $foo=5;

这里的代码不会在 or 运算符表达式后进行评估,因此输出将为 $foo=1。现在表达式是

$foo=false or $foo=5;

这里它将在 or 之后评估作为 = 更高的优先级,所以 $foo 将评估为 $foo=5,因此输出将为 5。但是当我们评估 $foo=false or true 时,它将考虑 = 更高的优先级,因此输出将为 $foo=false,但整个表达式将评估为 true,因为 false or true 变为 false


优先级是指分组,而不是评估顺序。正如deceze所解释的那样,“or”运算符始终首先评估其左参数,因为它是一个短路运算符。 - Barmar

2
<?php
$foo = false;
$foo or ($foo = '5');
echo $foo;
?>

请查看,您可以为$foo分配值“5”。

or =相比,它具有更高的优先级。这是事实.... :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接