1

注意:我知道这是不可接受的代码,我正在寻求理解解释器在做什么,而不是关于如何获得相同结果的建议!

从那以后,我已经阅读了足够多的内容,意识到我不能也不应该尝试使用 |,|| 或 XOR 来定义一个 switch 案例——所以请不要评论“不要那样做”的效果,我只是想了解解释器对这些语句做了什么并理解行为的奇怪之处。我正在使用 PHP 5.3.1。

这是我真正打算做的,现在正在使用,请不要推荐代码:

for ($i=0; $i<count($this->header); $i++) {
            switch($i) {
                case 0:
                    $this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : -5;   //angle from goal
                    break;
                case 1:
                    $this->header[$i] = $this->header[$i] ? $this->header[$i] : -5;         //miss penalty
                    break;
                case 2:
                    $this->header[$i] = $this->header[$i] ? $this->header[$i] : -10;         //miss penalty
                    break;
                case 3:
                    $this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : -10;  //error penalty
                    break;
            }
        }

但是很好奇我是否可以这样做:

for ($i=0; $i<count($this->header); $i++) {
            switch($i) {
                case 0 || 1:
                    $this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15;   //angle from goal
                    break;
                case 2 || 3:
                    $this->header[$i] = $this->header[$i] ? $this->header[$i] : -5;         //miss penalty
                    break;
            }
        }

而且,反常地,这确实运行了,但是非常慢(比如,几秒钟),尽管它当然(0||1)不会按照我想要的方式进行评估(实际上今天是关于按位运算符和逻辑运算符之间区别的课程)。

但对我来说更奇怪的是,我可以做到这一点,如果非常缓慢并且没有得到我想要的结果:

for ($i=0; $i<count($this->header); $i++) {
            switch($i) {
                case 0 XOR 1:
                    $this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15;   //angle from goal
                    break;
                case 2:
                    $this->header[$i] = $this->header[$i] ? $this->header[$i] : -5;         //miss penalty
                    break;
                case 3:
                    $this->header[$i] = $this->header[$i] ? $this->header[$i] : -5;         //miss penalty
                    break;
            }
        }

但我不能这样做:

for ($i=0; $i<count($this->header); $i++) {
            switch($i) {
                case 0 XOR 1:
                    $this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15;   //angle from goal
                    break;
                case 2 XOR 3:
                    $this->header[$i] = $this->header[$i] ? $this->header[$i] : -5;         //miss penalty
                    break;
            }
        }

这是 PHP 甚至不会评估的这些可怕的、可怕的想法中唯一的一个。

我的问题是:为什么评估这些语句需要这么长时间,为什么最后一个示例没有运行?我认为 PHP 正在解释 0 XOR 1 并比较trueand false,但我无法替换那些并让它仍然评估。有人知道这里发生了什么吗?谢谢!


更新:

评论要求一个var_dump($this->header)(如果不是很明显,我将我最初的 switch 语句从 7 个案例截断为 4 个,只是为了避免发送相同代码的垃圾邮件行,但是,鉴于var_dump()被要求,我选择发布整个事情以防万一揭示了我无法预见的事情!)。另外,是的,事实证明我一直在使用关联数组,因为array_values()在设置之前忘记调用$this->header,在下面的第二个答案中,出现此错误是为了解释switch语句的持续时间,而第一个答案和第二个一起回答是很好的逻辑演练。

array(12) {
  ["theZone"]=>
  NULL
  ["leftMiss"]=>
  NULL
  ["rightMiss"]=>
  NULL
  ["leftError"]=>
  NULL
  ["rightError"]=>
  NULL
  ["leftHit"]=>
  NULL
  ["rightHit"]=>
  NULL
  ["accuracy"]=>
  string(5) "false"
  ["rt"]=>
  string(4) "true"
  ["disease"]=>
  string(3) "yes"
  ["bars"]=>
  string(3) "yes"
  ["endMessage"]=>
  NULL
}
4

2 回答 2

2

case值必须是单个值。你不能这样做2 || 3,因为那会评估为

case (2 or 3) -> case TRUE

同样,如果你使用&&( and),你会得到

case (0 and 1) -> case FALSE

OR您可以对逻辑使用“失败”行为:

case 2:
case 3:
   ...code here ...
   break;

异或,你做不到。不是简单的案例陈述。

评论跟进:

for ($i = 0; $i < 5; $i++) {
   switch($i) {
       case 0 xor 1:  echo "0 xor 1: $i\n"; break;
       case 2 xor 3:  echo "2 xor 3: $i\n"; break;
   }
}

将输出

2x3: 0
0x1: 1
0x1: 2
0x1: 3
0x1: 4

php > var_dump(2 xor 3);
bool(false)
php > var_dump(0 xor 1);
bool(true)

请记住, switch 案例评估相同==。它们是惰性比较,而不是检查类型。因此,您2 xor 3的评估与 case has been 相同case false,这使得 $i=0 条件匹配。

于 2013-07-19T19:47:56.817 回答
1

哈哈,这很有趣,你在那里做了什么。

这不是让您陷入性能问题的开关。它可能是您的 for 循环与您的开关相结合。

我试图用给出的第二个例子来解释它。

但是,我只需要猜测,因此我必须假设您的 $this->header 数组如下所示(这将是您的性能泄漏的唯一原因):

$this->header = array(
  999 => 10,   // the value is irrelevant, only the key (2) matters
  998 => 15
);

现在让我们玩解释器调试器。

set $i to 0
is $i<count($this->header)? yes, because header size is 2
is ($i == (0 || 1))? no, because (0 == (0 || 1)) equals (0 == true) equals (false == true) can never be true
is ($i == (2 || 3))? no, because (0 == (2 || 3)) equals (0 == true) equals (false == true) will never comply
next loop, increment $i (set $i to 1)
is ($i<count($this->header)? yes, because header size is 2
is ($i == (0 || 1))? yes, because (1 == (0 || 1)) equals (1 == true) equals (true == true)
go into case statement
set $this->header[1] to -5  (remember the index 1 does not exist so far in your array)
next loop, increment $i (set $i to 2)
is $i<count($this->header)? yes, because header size is 3 (remember? you just added a new index which incremented your header size)
is ($i == (0 || 1))? yes, because (2 == (0 || 1)) equals (2 == true equals (true == true)
go into case statement
set $this->header[2] to -5 (again index 2 did not exist so far)
next loop, increment $i (set $i to 3)
is $i<count($this->header)? yes, because header size is 4 (again, you just added a new index)

现在这将一直持续到标头大小等于 $i。在上面的示例中,这将在 998 次迭代之后发生,因为这将是第一次不会创建新索引(现有的索引 - 998 - 将被简单地使用),从而导致 count($this->header ) 不变。

在您的第一个示例中,这不会发生。在第四次迭代后,标头大小将停止更改,因为 case 语句尝试比较整数值而不是布尔值。一旦它到达索引 5,它就会尝试与值 1、2、3 和 4 进行比较,并且不会匹配单个值,从而不会创建新的索引。

要解决性能问题,您应该确保数组中的每个键都存在,并更改您的 for 循环,如下所示:

$size = count($this->header);
for($i=0; $i<$size); $i++) {...}

当然,这不会解决您的逻辑问题。但既然你问发生了什么,我想这应该是一个很好的解释。

var_dump()-ing 你的 $this->header 数组在你的循环之前和之后应该证明我是对的:)

===

很抱歉删除和取消删除此答案。只是想确保它确实按照解释的方式运行。如果您可以为我提供标头数组的 var_dump,那就太好了。

于 2013-07-19T20:43:02.143 回答