【问题标题】:"if" versus "switch" [duplicate]“如果”与“开关”[重复]
【发布时间】:2011-03-24 21:45:58
【问题描述】:

可能重复:
is “else if” faster than “switch() case” ?

我最近遇到很多情况,我的条件非常简单,需要分支应用程序流。完成我正在做的事情的“最简单”方法只是一个普通的旧 if/elseif 声明:

if($value == "foo") {
    // ...
} elseif($value == "bar") {
    // ...
} elseif($value == "asdf" || $value == "qwerty") {
    // ...
}

...但我也在考虑类似的事情:

switch($value) {
    case "foo":
        // ...
        break;
    case "bar":
        // ...
        break;
    case "qwer":
    case "asdf":
        // ...
}

这似乎不太可读,但也许它的性能更高?但是,当条件中的“或”表达式越来越多时,switch语句似乎更具可读性和实用性:

switch($value) {
    case "foo":
        // ...
        break;
    case "bar":
    case "baz":
    case "sup":
        // ...
        break;
    case "abc":
    case "def":
    case "ghi":
        // ...
        break;
    case "qwer":
    case "asdf":
        // ...
}

我还看到了使用数组和函数对代码流进行分支的选项:

function branch_xyz() {/* ... */}
function branch_abc() {/* ... */}
function branch_def() {/* ... */}

$branches = array(
    "xyz"=>"branch_xyz",
    "abc"=>"branch_abc",
    "def"=>"branch_def"
);
if(isset($branches[$value])) {
    $fname = $branches[$value];
    $fname();
}

这最后一个选项可能还具有可分布在多个文件中的好处,尽管它非常难看。

您认为在性能、可读性和易用性方面,哪个优势最大,且折衷最少?

【问题讨论】:

  • 在您指定的情况下使用switch 更好。
  • 性能甚至没有真正考虑到它。首先编写可读代码,然后在必要时进行分析和优化。
  • 你可能想看看GOF Behavioral Patterns
  • @Dave 和@STW:我正在寻找关于可读性和使用适当性的答案,而不是严格的性能。

标签: php if-statement switch-statement branch


【解决方案1】:

我知道,微优化很糟糕。但我很好奇,我用这个脚本做了一个小基准测试:

<?php
$numof = 100000;
$file = fopen('benchmark.php', 'w');
if (!$file) die('file error');
fwrite($file, '<pre><?php' . "\n" . 'echo $i = $_GET[\'i\'], "\n";' . "\n");

fwrite($file,
'$start = microtime(true);
if ($i == 0) {}' . "\n");
for ($i = 1; $i < $numof; ++$i) {
    fwrite($file, 'elseif($i == '.$i.') {}'. "\n");
}
fwrite($file,
'echo \'elseif took: \', microtime(true) - $start, "\n";' . "\n");

fwrite($file,
'$start = microtime(true);
switch($i) {' . "\n");
for ($i = 1; $i < $numof; ++$i) {
    fwrite($file, 'case '.$i.': break;'. "\n");
}
fwrite($file,
'}
echo \'switch took: \', microtime(true) - $start, "\n";' . "\n");

结果数据(对于 numof = 100000):

i: 0
elseif took: 6.2942504882812E-5
switch took: 3.504753112793E-5

i: 10
elseif took: 6.4849853515625E-5
switch took: 4.3869018554688E-5

i: 100
elseif took: 0.00014805793762207
switch took: 0.00011801719665527

i: 1000
elseif took: 0.00069785118103027
switch took: 0.00098896026611328

i: 10000
elseif took: 0.0059938430786133
switch took: 0.0074150562286377

i: 100000 (first non-existing offset)
elseif took: 0.043318033218384
switch took: 0.075783014297485

我用 PHP 5.3.1 或 5.3.2 在我的旧的慢速 windows 机器上运行了脚本,我不知道是不是知道。

【讨论】:

  • +1 用于实际尝试测量性能差异以对问题提出的问题给出有效答案。
【解决方案2】:

就我个人而言,我发现这个开关更具可读性。原因如下:

if ($foo == 'bar') {
} elseif ($foo == 'baz') {
} elseif ($foo == 'buz') {
} elseif ($fou == 'haz') {
}

这样浓缩,你可以很容易地看到行程(无论是错字还是诚实的差异)。但是有了开关,你就知道是什么意思了:

switch ($foo) {
    case 'bar': 
        break;
    case 'baz': 
        break;
    case 'buz': 
        break;
    case 'haz': 
        break;
}

另外,更容易阅读:

if ($foo == 'bar' || $foo == 'baz' || $foo == 'bat' || $foo == 'buz') {
}

case 'bar':
case 'baz':
case 'bat':
case 'buz':
    break;

从性能的角度来看...好吧,不用担心性能。除非你在一个紧密的循环中做几千个,否则你甚至无法分辨出差异(差异可能在微秒范围内,如果不是更低的话)。

选择你认为最易读的方法。这是重要的部分。不要试图进行微优化。记住,Premature Optimization Is The Root Of All Evil...

【讨论】:

  • 请注意,由于loose comparison,switch 会给您 false 否定和误报。在这里,switch 是代码异味和安全祸根 ipso facto。请改用数组键。
  • @Pacerier,为什么 switch 是安全问题?
  • @ryabenko-pro,松散的比较会给你带来微妙的错误:switch(0){case null: echo 'null'; break; default: echo 'not null';}
【解决方案3】:

您应该考虑使用多态性来替代 if 或 switch 等控制结构。如果您有很多选项,则特别方便,因为它可以大大简化控制逻辑。

我在这里写过这个概念:http://codeutopia.net/blog/2009/02/02/avoiding-endless-switch-case-structures-with-classes/

【讨论】:

    【解决方案4】:

    Switch 告诉后来的读者,您是基于单个值的值进行分支的,他们必须通过查看所有条件来暗示这一点。所以为了清晰起见,我更喜欢开关

    【讨论】:

      猜你喜欢
      • 2010-10-01
      • 2021-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多