进行PHP转换的最佳方法是每个案例有多个值?


70

您将如何执行此PHP switch语句?

还要注意,这些都是较小的版本,我需要创建的版本1将添加更多的值。

版本1:

switch ($p) { 
    case 'home': 
    case '': 
        $current_home = 'current';
    break; 

    case 'users.online': 
    case 'users.location': 
    case 'users.featured': 
    case 'users.new': 
    case 'users.browse': 
    case 'users.search': 
    case 'users.staff': 
        $current_users = 'current';
    break;

    case 'forum': 
        $current_forum = 'current';
    break; 
} 

版本2:

switch ($p) { 
    case 'home': 
        $current_home = 'current';
    break; 

    case 'users.online' || 'users.location' || 'users.featured' || 'users.browse' || 'users.search' || 'users.staff': 
        $current_users = 'current';
    break;

    case 'forum': 
        $current_forum = 'current';
    break; 
} 

更新-测试结果

我对10,000次迭代进行了速度测试,

Time1:0.0199389457703 // If语句
Time2:0.0389049446106 // switch语句
Time3:0.106977939606 //数组


32
第2版​​不符合您的想法。
太多的PHP

6
版本2不起作用,请在此处阅读更多信息:nutt.net/2004/12/28/multiple-cases-for-switch-construct
GusDeCooL 2012年

@jasondavis如果您使用变量变量,那么您将拥有一个既小又简单的代码,就像我喜欢的那样=)查看我的答案,它已经过测试并且可以工作。
奥马尔2012年

Answers:


53

在任何情况下,如果您有未知的字符串,并且需要弄清楚它匹配的是其他字符串中的哪一个,那么添加更多项时不会变慢的唯一解决方案是使用数组,但要拥有所有可能的字符串作为键。因此,您的交换机可以替换为以下组件:

// used for $current_home = 'current';
$group1 = array(
        'home'  => True,
        );

// used for $current_users = 'current';
$group2 = array(
        'users.online'      => True,
        'users.location'    => True,
        'users.featured'    => True,
        'users.new'         => True,
        'users.browse'      => True,
        'users.search'      => True,
        'users.staff'       => True,
        );

// used for $current_forum = 'current';
$group3 = array(
        'forum'     => True,
        );

if(isset($group1[$p]))
    $current_home = 'current';
else if(isset($group2[$p]))
    $current_users = 'current';
else if(isset($group3[$p]))
    $current_forum = 'current';
else
    user_error("\$p is invalid", E_USER_ERROR);

这看起来不像的干净switch(),但这是唯一快速的解决方案,其中不包括编写小的函数和类库来保持整洁。向数组添加项目仍然非常容易。


1
从技术上来说是正确的,随着您添加更多项,它会变慢,它只会变得越来越慢-哈希表非常快,但它们不是魔术师:-)
moodboom

26

版本2不起作用!

case 'users.online' || 'users.location' || ...

与以下内容完全相同:

case True:

并且case将为的任何值选择$p,除非$p是空字符串。

||case语句内没有任何特殊含义,您没有在与$p每个字符串进行比较,只是在检查是否不是False


好的,您是否认为使用switch或if语句会更快,然后创建多个数组并多次检查某个值是否在数组中?
贾森·戴维斯(JasonDavis)2009年

我从未听过或读过任何使我认为switch()会更快的东西。路由仍将进行整个字符串比较。
太多的PHP

这里是一些节目阵列可能会比较慢stackoverflow.com/questions/324665/...
JasonDavis

8

将这么多的值放入数组中并查询该数组,因为切换情况似乎隐藏了当使用字符串变量作为条件时您要实现的目标语义,从而使其更难以阅读和理解,例如:

$current_home = null;
$current_users = null;
$current_forum = null;

$lotsOfStrings = array('users.online', 'users.location', 'users.featured', 'users.new');

if(empty($p)) {
    $current_home = 'current';
}

if(in_array($p,$lotsOfStrings)) {
    $current_users = 'current';
}

if(0 === strcmp('forum',$p)) {
    $current_forum = 'current';
}

+1第一次阅读问题时,首先想到的是这种解决方案。随着案例数量的增加,您所要做的就是向数组添加值,并依靠in_array来完成它的工作。
拉德尔2009年

以我的方式这样做,我将有许多不同的数组,因此我将对几个数组进行in_array,您认为一种方法相对于另一种方法有任何性能提升吗?
杰森·戴维斯(JasonDavis)2009年

我没有尝试过对其进行基准测试,它更易于阅读,尤其是您将使用常量时。您希望使用多少个不同的阵列(和大小)?
拉德尔2009年

我认为性能上不会有任何明显的差异。即使有,我仍然会坚持上述内容,因为就可读性和可维护性而言,这对我来说更有意义。
karim79

@Randell这用于hgih交通站点上的菜单选择器,因此将只有大约8个数组,其中一些数组每个数组最多可以包含15个项目,我知道这不是很大的,但正在做的额外工作是将会有很多流量,并且这将在每个页面加载时完成。那就是为什么我要问
JasonDavis

6

为了完整起见,我将指出,可以用有效的switch语句替换损坏的“ Version 2”逻辑,并且可以使用数组来提高速度和清晰度,如下所示:

//用于$ current_home ='current';
$ home_group =数组(
    'home'=>是的,
);

//用于$ current_users ='current';
$ user_group =数组(
    'users.online'=>是的,
    'users.location'=>是的,
    'users.featured'=>是的,
    'users.new'=>是的,
    'users.browse'=>是的,
    'users.search'=>是的,
    'users.staff'=>是的,
);

//用于$ current_forum ='current';
$ forum_group =数组(
    '论坛'=>是的,
);

切换(true){
    大小写isset($ home_group [$ p]):
        $ current_home ='当前';
        打破;
    大小写isset($ user_group [$ p]):
        $ current_users ='当前';
        打破;
    大小写isset($ forum_group [$ p]):
        $ current_forum ='当前';
        打破;
    默认:
        user_error(“ \ $ p无效”,E_USER_ERROR);
}    

4

如果有人要维护您的代码,几乎可以肯定他们会对版本2进行双重修改-这是非常不标准的。

我会坚持使用第1版。尽管这种情况下没有自己的陈述框的案例陈述应该在其// fall through旁边有一个明确的注释,以表明确实是您的意图,从而消除了是否含糊其辞的意图您将以不同的方式处理案件而忘记了什么。


4

尚未提及的其他一些想法:

switch(true){ 
  case in_array($p, array('home', '')): 
    $current_home = 'current'; break;

  case preg_match('/^users\.(online|location|featured|new|browse|search|staff)$/', $p):
    $current_users = 'current'; break;

  case 'forum' == $p:
    $current_forum = 'current'; break; 
}

可能有人会抱怨#2的可读性问题,但是继承这样的代码我没有问题。


有趣的是,我的一个伙伴向我发送了非常相似的代码,说它可以工作,我立即来到Stack Overflow,看看是否有人认为这是解决方案。我认为这很酷
samrap '16

整洁的实现。
Hayatu Mohammed Abubakar

3

第1版肯定会更容易看清楚,更清楚您的意图,并且更容易添加案例条件。

我从未尝试过第二版。在许多语言中,这甚至都不会编译,因为每种情况下的标签都必须求值为常量表达式。


2

如今,您可以...

switch ([$group1, $group2]){
    case ["users", "location"]:
    case ["users", "online"]:
        Ju_le_do_the_thing();
        break;
    case ["forum", $group2]:
        Foo_the_bar();
        break;
}

1

我绝对更喜欢版本1。版本2可能需要更少的代码行,但是一旦您有很多如您所预测的值,将很难阅读。

(老实说,直到现在我都还不知道版本2是合法的。我以前从未见过这样做。)


1

没有版本2不能真正起作用,但是如果您想要这种方法,则可以执行以下操作(可能不是最快的方法,但是可以说更直观):

switch (true) {
case ($var === 'something' || $var === 'something else'):
// do some stuff
break;
}


根本不直观。可以用一个简单的if语句代替。
kbanman 2014年

1

也许

        switch ($variable) {
        case 0:
            exit;
            break;
        case (1 || 3 || 4 || 5 || 6):
            die(var_dump('expression'));
        default:
            die(var_dump('default'));
            # code...
            break;
    }

1
最好,如果您做出一些解释您的答案并重新设置您的代码格式
硕大的


0
if( in_array( $test, $array1 ) )
{
    // do this
}
else if( stristr( $test, 'commonpart' ) )
{
    // do this
}
else
{
    switch( $test )
    {
        case 1:
            // do this
            break;
        case 2:
            // do this
            break;
        default:
            // do this
            break;
    }
}

0

结合变量变量进行切换将为您提供更大的灵活性:

<?php
$p = 'home'; //For testing

$p = ( strpos($p, 'users') !== false? 'users': $p);
switch ($p) { 
    default:
        $varContainer = 'current_' . $p; //Stores the variable [$current_"xyORz"] into $varContainer
        ${$varContainer} = 'current'; //Sets the VALUE of [$current_"xyORz"] to 'current'
    break;

}
//For testing
echo $current_home;
?>

要了解更多,结账变量变量和实施例I提交PHP手册:
实施例1http://www.php.net/manual/en/language.variables.variable.php#105293
实施例2HTTP:// WWW .php.net / manual / en / language.variables.variable.php#105282

PS:这个示例代码小而简单,就像我喜欢的那样。经过测试也可以使用


1
OP正在询问通常如何case最有效地组合多个条件。
jprofitt 2012年

0

您只是在寻找字符串中的常见模式。我本以为正则表达式将是一种更有效的方法,因为PHP使用preg_match实现了此功能,因此编写的代码很少,而且速度可能更快。例如:

case preg_match('/^users./'):
// do something here
break;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.