PHP中switch语句在整数为0时出错。

4

我在php的switch case中遇到了问题。

当我设置$number=0时,它应该运行第一个case,但是这段代码返回了在第二个case中的10-20K

我检查了比较运算符,在if else中测试它们会返回正确的值,但是这里第一个case不会在$number=0上运行。

为什么会发生这种情况?php将0视为false或代码有误吗?

代码pad粘贴链接http://codepad.org/2glDh39K

以下是代码:

<?php

$number = 0;

    switch ($number) {
     case ($number <= 10000):
            echo "0-10K";
           break;
        case ($number > 10000 && $number <= 20000):
            echo "10-20K";
            break;
        case ($number > 20000 && $number <= 30000):
            echo "20-30K";
            break;
        case ($number > 30000 && $number <= 40000):
            echo "30-40K";
            break;
        case ($number > 40000 && $number <= 50000):
            echo "40-50K";
            break;
        case ($number > 50000 && $number <= 60000):
            echo "50-60K";
            break;
        case ($number > 60000 && $number <= 70000):
            echo "60-70K";
            break;
        case ($number > 70000 && $number <= 80000):
            echo "70-80K";
            break;
        case ($number > 80000 && $number <= 90000):
            echo "80-90K";
            break;
        case ($number > 90000):
            echo "90K+";
            break;

        default: //default
            echo "N/A";
            break;
}

?>
7个回答

7

你差不多使用了switch的相反方式,但还没有完全正确。你需要通过写switch(true)来完全倒转它:

switch (true) { // IMPORTANT CHANGE HERE!
    case ($number <= 10000):
        echo "0-10K";
       break;
    case ($number > 10000 && $number <= 20000):
        echo "10-20K";
        break;
    // etc
}

或者将整个代码块改写为 if/else:
if ($number <= 10000) {
    echo "0-10K";
else if ($number > 10000 && $number <= 20000) {
    echo "10-20K";
}
// etc

两个重要的注意事项:

  1. 反向 switch 在第一次见到时通常看起来非常不直观。如果您感觉不舒服,请不要使用它。
  2. 您的条件语句可以简化——假设它们按顺序出现,每个 $number > X 部分都已经被上一个条件语句中的检查($number <= X)排除掉了。然而,也有人认为保留这些检查可以使代码在修改时更加健壮。

4
switch ($number) {
 case ($number <= 10000):   // check $number == ($number <= 10000)
       echo "0-10K";
       break;
 // you hit the below because `0 == false` is true in php
 case ($number > 10000 && $number <= 20000): // check $number == ($number > 10000 && $number <= 20000)
        echo "10-20K";
        break;
 // ...

但是你可以用更少的代码实现它:
function showRange($number) {
    if ($number > 90000) {
       echo "90K+";
       return;
    }
    echo sprintf("%s-%sK", (int) ($number / 10000) * 10, ((int) ($number / 10000) +1) * 10 );
}

更简单?在我看来并不是这样。代码更少 - 是的,但可读性受到了影响。 - Lix
@Lix 好的,这只是个人口味问题。 - xdazz
@JagdeepSingh:因为有时候一行代码并不具有描述性,在三、四、五个月后,你可能完全不知道这段代码是干什么的。 - Madara's Ghost
@MadaraUchiha - 是的,但我认为这就是编程语言中注释的用途。 - Jagdeep Singh

3
$number = 0;
var_dump($number); // int(0)

如果您将语句修改为case ($number > 0 && $number <= 10000):,它会奇妙地工作。但是,它可以与输入的任意查找($number > 9091 && $number <= 10000)一起使用。

即使是以下完全错误的代码:

$number = 0;
$jonskeet = false;

switch ($number)
{
    case ($jonskeet === true && $number <= 10000):
        echo "0-10K";
        // ...

即使在if语句中相同的条件不起作用,它也会输出0-10K

问题在于,不应该将select与长条件一起使用。select可用于执行某些操作,如果变量的值等于case关键字后面的内容,则可以使用select。请参见:

select ($user_rank)
{
    case 0:
        return "guest";
        break;
    case 1:
        return "user";
        break;
    // ...
    default:
        return "unknown";
        break;
}

但是你在你的代码的case中有很长的条件。

case ($number <= 10000):
    echo "0-10K";
    break;
case ($number > 10000 && $number <= 20000):
    echo "10-20K";
    break;

运行此代码会将$number <= 10000翻译为TRUE,将$number > 10000 && $number <= 20000翻译为FALSE,就像两个语句一样。然后,您的代码按以下方式执行:
case TRUE:
    echo "0-10K";
    break;
case FALSE:
    echo "10-20K";
    break;

$number0,但它也可以评估为 FALSE,这就是为什么你得到了不期望的输出。

作为解决方案,你应该将代码转换为具有 if-elseif-else 结构:

 if ( $number < 10000 ) {
     echo "0-10K";
 } else if ( $number > 10000 && $number <= 20000 ) {
     echo "10-20K";
 // ...
 } else {
     echo "N/A";
 }

3
当您执行switch case方法时,不能像那样匹配布尔值。您只需要比较结果值即可。
我认为您应该重写代码以使用if...then...elseif语句。
if ($number <= 10000){
  echo "0-10K";
}elseif($number <= 20000){
  echo "10-20K";
}elseif($number <= 30000){
  echo "20-30K";
}elseif($number <= 40000){
  ...
}

通过使用这种方法,您无需每次进行两个检查,因为前面的if语句也会检查这些条件。例如:如果您到达第二个if语句,则已经知道该值不是小于(或等于)1000,因此它必须大于10000

1

在这里,如果 $i 等于 0,PHP 将执行所有的 echo 语句!

因此,它会执行下一个 case 的语句,在那个 case 中有 break,所以跳出了 switch。

因此,应该使用 if-else-if 而不是 switch case。

if ($number <= 10000){
  echo "0-10K";
}elseif(  $number <= 20000){
  echo "10-20K";
}elseif(  $number <= 30000){
  echo "20-30K";
}elseif(  $number <= 40000){
  echo "90K+";
}

 ...

elseif(  $number <= 90000)
     echo "80-90K";

}elseif($number > 90000){
echo "90K+";
}

不需要进行那些额外的测试。如果我们已经到了第二个if语句,那么我们已经知道这个值大于10000了... - Lix
@Lix 我的意思是,如果在 switch 中有 0,则所有 case 都将被执行。 - Database_Query
@hakra - 首先感谢您的回答 :)在 switch 中,如果有 0,则会执行第二个 case 然后 break; 因为在第一个 case 中,它将检查 $number(0 作为 false)==($number <= 10000)(作为 true)// 所以 false == true // 结果为 false同样的条件在第二个 case 中也成立,这就是为什么它会执行第二个 case。谢谢 :) - Jagdeep Singh

1

是的,对于PHP来说,0就是FALSE(除非你使用===)。而且,是的,你的代码是错误的 - switch不是用来比较范围的,它是用来比较值的(至少在PHP中,在Ruby或Perl 6中另当别论),像这样。

switch ($letter) {
case 'a':
    echo "A?";
    break;
default:
    echo "Unknown letter";
    break;
}

在您的情况下,您将数字与条件进行比较 - 这些条件要么返回true,要么返回false。由于0false,因此第二个条件被捕获。 switch不适用于这样的代码,我建议使用if else或重写您的逻辑 - 重复不是一个好主意。
$range_number = floor($number / 1000);
echo $range_number, $range_number ? "K" : "", "-", $range_number + 1, "K";

(顺便说一句,我知道switch (true)是可以工作的,但不要使用它——这是一个丑陋的hack)

0

你不能真正地使用 switch case 处理数字范围。请使用 if(){} else{} 来实现此目的。


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