【问题标题】:understanding assignment inside condition solving precedence [closed]理解条件解决优先级内的分配[关闭]
【发布时间】:2012-11-21 22:22:42
【问题描述】:

今天在工作中,我被困在一行代码中,我无法理解。 我在 JavaScript 中有一个函数,为了确保获得唯一的时间戳,我做了那个丑陋的循环:

var ts = +new Date();
while (ts === (ts = +new Date()));

我认为很清楚我们正在重新设置 ts 直到它的值变得不同。

但是当我尝试将函数迁移到 PHP 代码时 - 就像这样:

$ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime());
//regex extracts digits and re-positions them - ugly microtime :(
while ($ts === ($ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime())));

解释器进入一个无限循环。我所有的尝试似乎都表明 $ts 分配是在比较之前进行的,但我不明白为什么没有首先解决左侧表达式。我的 PHP 知识没有我的 JavaScript 知识那么大,所以我想知道是否有一些关于我泄露的 PHP 表达式和语句的关键提示。

建议:我不想通过制作“结构良好”的循环来修复我的代码 - 解决方案很明显 - 我很想了解这里发生了什么。非常感谢所有帮助。

【问题讨论】:

  • 这里有一个聪明的老人给你的一些建议:“调试的难度是一开始写代码的两倍。因此,如果你尽可能巧妙地编写代码,你就是,根据定义,它不够聪明,无法调试它。” ——布赖恩·克尼汉
  • 解决方案对你来说可能很明显,但对我来说并不明显,即使我认为自己是一个高于平均水平的程序员并且在过去 15 年里一直这样做。此外,如果我团队中的任何人想出这个,我会告诉他们将其重写为更易读的结构。
  • 坦克 Botond Balázs 和 GolezTrol。我非常喜欢良好的编程技术 - 当我说我使用例如 JSlint 来构建我的 JavaScript 时,请相信我。这只是一个快速测试,但当我遇到这个令人惊讶的问题时,我无法停止思考。
  • @Áxel:这确实是一个令人惊讶(而且非常有趣)的问题。
  • 我阅读“运算符优先级”页面的次数越多,我认为我就越了解 PHP 人员想要传输的内容......在下面回答或这个Parentheses may be used to force precedence, if necessary.。明天我会尝试做一些测试,并强制两个选项中的一个来证明自己是错误的,然后考虑另一个作为最终解释,我会带着投票回来 - 你让这件事变得非常困难:你们都不是给出了一个明确的答案,但你非常乐于助人;谢谢! =)

标签: php loops expression variable-assignment


【解决方案1】:

PHP 需要先评估赋值,然后才能进行比较。通常,赋值运算符的优先级很低,所以当你写$a = $b + $c时,首先计算加法,然后再将结果赋给$a。 不过,这是一个特例,虽然似乎没有很好地记录在案,但在文档中发现了一个类似的案例,说明:

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

所以在这种情况下,PHP 确定它需要先进行赋值,然后才能否定赋值的结果。我认为这里正在发生类似的事情,尽管 PHP 应该能够稍后进行分配是对的。

实际上,结果可能是不可预测的,就像其他一些表达式一样:

// mixing ++ and + produces undefined behavior
$a = 1;
echo ++$a + $a++; // may print 4 or 5

【讨论】:

  • 最后,你是对的:括号不是原因:while (($ts) === ($ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime()))); 一直循环;甚至while (($ts) === $ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime())); 一直在循环,但愚蠢的while (($ts = $ts) === ($ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime()))) 是的,是的!
【解决方案2】:

PHP 将在比较之前评估分配,所以当它执行$ts === 时,$ts = 已经发生了。这是一个快速修复:

$ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime());

//regex extracts digits and re-positions them - ugly microtime :(
while ($ts === ($ts2 = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime()))) {
    $ts = $ts2;
}

此外,PHP 有一个名为 uniqid() 的便捷函数,它可以为您做类似的事情。它每次都会给你一个唯一的字符串。

【讨论】:

  • 我已经知道它是这样工作的,我已经忍受了将近一个小时;)我很想知道为什么,php文档中解释评估优先级的任何参考案例或类似的东西。顺便说一句,非常感谢 uniquid()
  • 它确实首先评估了分配。表达的顺序不会以任何方式影响它。如果你写while (($ts = ...) === $ts),脚本也会挂起。
  • PHP 太奇怪了。我不想知道代码库一定是多么糟糕的一团糟才会出现如此奇怪的问题。
猜你喜欢
  • 1970-01-01
  • 2012-12-21
  • 1970-01-01
  • 2017-12-21
  • 1970-01-01
  • 2015-03-09
  • 1970-01-01
  • 2021-04-26
  • 1970-01-01
相关资源
最近更新 更多