在PHP的“switch”语句中使用比较运算符

63

我有四个条件需要经过,并且我认为在PHP中使用 switch 语句是最好的选择。但是,我需要检查一个整数是否小于等于、大于等于等等。

switch ($count) {
    case 20:
        $priority = 'low';
        break;

    case 40:
        $priority = 'medium';
        break;

    case 60:
        $priority = 'high';
        break;

    case 80:
        $priority = 'severe';
        break;
}

如果使用if()语句,则会像下面这样:

if ($count <= 20) {
    $priority = 'low';
} elseif ($count <= 40) {
    $priority = 'medium';
} elseif ($count <= 60) {
    $priority = 'high';
} else {
    $priority = 'severe';
}

switch-case 中是否可能实现这个功能?


8
你可以使用switch(true)并在满足范围的情况下返回true 示例。如果这只是一个小规模的问题,你可以在范围内重复数字,并让它们相互衔接 示例。但是对于你的例子,你应该使用if语句。 - Dave Chen
@DaveChen 这是个不错的技巧。 - Havenard
根据这个,显然你可以 -- 搜索(随机器)-- http://php.net/manual/en/control-structures.switch.php。 - Tasos
6个回答

178

解决这个问题的一般情况是:

switch (true) {
    case $count <= 20:
        $priority = 'low';
        break;

    case $count <= 40:
        $priority = 'medium';
        break;

    case $count <= 60:
        $priority = 'high';
        break;

    default:
        $priority = 'severe';
        break;
}

12
在我看来,使用脚本膨胀的开关块的唯一原因(也是全部原因)是执行值的单个评估并查找满足条件的情况。这个“解决方案”抛弃了这个优点,为了满足true而执行多个评估,因此和if-elseif-else块一样效率低下,同时代码还会更加臃肿。我建议采用像Havenard的计算查找这样的方法,它简明易懂、易于维护、高效且高度可扩展。 - mickmackusa
另一种解决方案仅适用于可以预先计算范围的情况。该解决方案非常适用于任意选择的范围。想象一下,时间差以秒为单位,并且您声明了像“超过1年前”,“超过1个月前”,“几天前”,“昨天”,“几小时前”,“几分钟前”,“几秒钟前”,“刚刚”这样的块。这需要在此答案中说明的解决方案。 - Xavi Montero
另外,除了第一个等式表达式保持不变的if-else链之外,switch是什么?经典的switch($a){case 3:aaa;break;case 5:bbb;break;default:zzz;break;}实际上是一个if $a == 3则执行aaa,else-if $a == 5则执行bbb,否则执行zzz。这里的解决方案实际上是一个更紧凑的表示法,即如果 true == ($count <= 20) 则执行aaa,else-if true == ($count <=40) 则执行bbb,否则如果 true == ($count <=60) 则执行ccc,否则执行zzz。没有任何问题,对吧? - Xavi Montero
这是一个奇怪的 switch() 用法,在大多数语言中,每个 case 必须是一个常量字面量。很奇怪看到PHP支持这样做。 - Havenard

12

交换机无法做到这一点,但在这种特定情况下,您可以尝试以下操作:

switch ((int)(($count - 1) / 20)) {
    case 0:
        $priority = 'low';
        break;
    case 1:
        $priority = 'medium';
        break;
    case 2:
        $priority = 'high';
        break;
    case 3:
        $priority = 'severe';
        break;
}

因此,在(int)(($count - 1) / 20)中,从0到20的所有值都将计算为0,从21到40的所有值都将计算为1,以此类推,这使您可以使用switch语句来实现此目的。

而且,由于我们正在连接值,因此甚至可以简化为一个数组:

$priorities = ['low', 'medium', 'high', 'severe'];
$priority = $priorities[(int)(($count - 1) / 20)];

1
你不需要将其转换为整数,因为PHP不允许使用浮点键 - 它们会自动截断为整数。 https://3v4l.org/R1kL1 - mickmackusa
3
@mickmackusa 嗯...无论如何,我认为将代码未来化是明智的选择,不要依赖于模糊的转换。 - Havenard
不错的效率技巧 - 我喜欢它 :) - John Ruiz
3
@Havenard,你的预言已经实现了!最好现在明确地进行转换。 - mickmackusa

9

有一种在PHP 7中使用三元赋值运算符的方法。该运算符早在(5.4?)就被引入了,但我从未在其他版本上测试过代码。我在这里编写了整个switch代码,但为了简洁起见,这里只是特定子句。假设我们希望条件匹配所有大于或等于五的数字:

switch($value){
    case ($value >= 5 ? $value : !$value): // Do something here
    break;
}

我们要么保持$value不变,要么根据条件对其进行取反。$value始终与自身匹配,或者在与其取反的测试中失败。


可以确认这种方法适用于至少php 5.5。 - Ole Haugset

2

不,switch()语句用于进行多个相等性测试。它们基本上只是稍微容易阅读一些(但也更危险)的版本。

if (x == 'a') { ... }
else if (x == 'b') { ... } 
else if (x == 'c') { ... }

代码。无法将switch()==更改为<或任何其他比较运算符。它严格用于相等性测试。


1
@MacGyver在他的解决方案中仍然在switch语句中使用"=="。例如,他的代码正在检查(($count <= 20) == true)。 - Sam Dean

1
使用三元运算符:

使用 三元运算符

$priority =
    // "switch" comparison for $count
    $count <= 20 ? 'low' :
    ($count <= 40 ? 'medium' :
    ($count <= 60 ? 'high' :
    // default above 60
    'severe'));

我知道三元运算符很难理解,但使用简单的?:实际上非常容易。
它的操作方式类似于Excel的“If”公式:
=IF( logical_test, value_if_true, value_if_false )

$variable = logical_test ? value_if_true : value_if_false

你可以嵌套 if 语句(在第一个语句的“value_if_false”部分放置第二个 ?: ),这会使阅读时变得混乱,但当你逐行书写时,就不会那么困惑了,就像上面所示。

我上面的代码基本上相当于 OP 编写的 if() 语句。


哦,我在发布之前没有看到@bytephunk使用三元运算符。 - milkncookie

-1

我可以确认bytepunk的答案在这里是可行的。

此外,使用PHP 7扩展概念:

switch ($interval->days)
{
    case 0:
        return '1 day';
        // break;
    case (($interval->days >= 1 && $interval->days <= 7) ?? $interval->days):
        return '1 week';
        // break;
    case (($interval->days >= 8 && $interval->days <= 31) ?? $interval->days):
        return '1 month';
        // break;
    case (($interval->days >= 31 && $interval->days <= 93) ?? $interval->days):
        return '2-3 months';
        // break;
    default:
        return '3+ months';
}

我承认这不是最干净的代码,因此可能将每个情况都用类似静态纯函数的方式包装起来会使事情变得更整洁一些,并且不要忘记为每个函数命名(或创建一个带参数的通用函数)以匹配情况。这将使它更易读。

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