【问题标题】:Understanding operator precedence in php了解php中的运算符优先级
【发布时间】:2013-08-29 19:27:27
【问题描述】:

我有以下代码在生产中似乎导致了无限循环。

 $z=1;
 while (!$apns = $this->getApns($streamContext) && $z < 11)
 {
    myerror_log("unable to conncect to apple. sleep for 2 seconds and try again");
    $z++;
    sleep(2);
 }

如何应用导致此行为的优先规则?

http://php.net/manual/en/language.operators.precedence.php

我在文档中看到了这个注释:

虽然 = 的优先级低于大多数其他运算符,但 PHP 会 仍然允许类似于以下的表达式: if (!$a = foo()), in 这种情况下 foo() 的返回值被放入 $a 中。

这让我认为应该首先评估 =。然后!然后是&&,不会导致死循环。

【问题讨论】:

  • 您的意思是在 while 循环中使用 ==(比较)而不是 =(赋值)吗?
  • 不,那句话真的只是意味着=左边的!是有效的。 &amp;&amp; 仍然是分配值的一部分。
  • 也:没有。坏的。不要这样编码。太可怕了。
  • 添加一些括号总是一个好主意,这样代码就清晰了,没有这些问题...
  • 我知道代码很糟糕......它甚至不是我的。但这个问题很有趣。我这里有一个无限循环。为什么?

标签: php operators operator-precedence


【解决方案1】:

你的代码是这样评估的:

while (!($apns = ($this->getApns($streamContext) && ($z < 11))))

这就是您看到无限循环的原因(只要$z &gt;= 11$apns 为假,因此条件始终为真)。这种优先级的原因是特殊规则仅适用于有效分配左侧!(优先级低于=)。它对右边的布尔运算符没有影响,它的行为就像在任何理智的语言中一样。

你的风格很糟糕。试试这个,它更具可读性,只是$z 的最终值不同(如果这很重要,你可以调整break 语句。

for( $z = 1; $z < 11; ++ $z ) {
    // note extra brackets to make it clear that we intend to do assignment not comparison
    if( ($apns = $this->getApns($streamContext)) ) {
        break;
    }
    myerror_log("unable to conncect to apple. sleep for 2 seconds and try again");
    sleep(2);
}

【讨论】:

  • 所以在我看来 $apns 除了布尔值之外永远不会分配任何东西。对?连接到苹果并发送推送消息的其余代码将永远无法工作。
  • $apns 会得到getApns 返回的任何东西。这是一种常见的模式;它实际上是在等到$apns 为真(即非空),然后继续执行代码。请注意,由于比较是在赋值之后应用的,所以它对$apns 中的值没有影响。但是,如果您想通过将分配与条件分开来使这一点更清楚,那也很好。
  • 与我之前的评论(现在已编辑)相反,PHP 的 &amp;&amp;|| do 将值转换为 truefalse,因此您的初始代码总是会在$apns 中添加truefalse,这意味着它永远不会工作。我发布的代码将起作用。
  • ! 运算符的优先级高于表达式中的所有其他运算符。这是将被评估的第一件事,并且没有任何意义。 !$apns = $this-&gt;getApns($streamContext) &amp;&amp; ($z &lt; 11) 的结果与$apns = $this-&gt;getApns($streamContext) &amp;&amp; ($z &lt; 11) 相同。例如,试试这个代码!$a = true; echo $a;$a 的值将是 true,而不是 false
  • @hdvianna 不用担心。 PHP 是一团乱七八糟的傻事。互联网上有很多页面专门讨论其奇异的特殊情况。
【解决方案2】:

您的代码清楚地说明了为什么 总是 将所有条件放在括号中是一个好习惯(代码块也是如此。即使是单行符也应该被 {} 包围)。所以而不是容易出错:

while (!$apns = $this->getApns($streamContext) && $z < 11)

while (!($apns = $this->getApns($streamContext)) && ($z < 11))

你会安全的。

【讨论】:

    猜你喜欢
    • 2014-09-09
    • 2012-08-10
    • 2018-04-02
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多