"if"与"switch"

mat*_*sta 14 php branch if-statement switch-statement

可能重复:
"else if"比"switch()case"快吗?

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

if($value == "foo") {
    // ...
} elseif($value == "bar") {
    // ...
} elseif($value == "asdf" || $value == "qwerty") {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

......但我也在考虑这样的事情:

switch($value) {
    case "foo":
        // ...
        break;
    case "bar":
        // ...
        break;
    case "qwer":
    case "asdf":
        // ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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();
}
Run Code Online (Sandbox Code Playgroud)

最后一个选项也可能具有可跨多个文件分发的好处,尽管它非常难看.

在性能,可读性和易用性方面,您认为哪一方面最具优势?

Nik*_*kiC 45

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

<?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");
Run Code Online (Sandbox Code Playgroud)

产生的数据(对于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
Run Code Online (Sandbox Code Playgroud)

用PHP 5.3.1或5.3.2在旧的和慢速的Windows机器上运行脚本,dunno是对的.

  • +1做某事实际尝试衡量性能差异,给出问题所要求的有效答案. (10认同)

irc*_*ell 27

就个人而言,我觉得这个开关更具可读性.原因如下:

if ($foo == 'bar') {
} elseif ($foo == 'baz') {
} elseif ($foo == 'buz') {
} elseif ($fou == 'haz') {
}
Run Code Online (Sandbox Code Playgroud)

像这样凝聚,你可以很容易地看到旅行(无论是拼写错误还是诚实的差异).但是通过一个开关,你可以隐含地知道它是什么意思:

switch ($foo) {
    case 'bar': 
        break;
    case 'baz': 
        break;
    case 'buz': 
        break;
    case 'haz': 
        break;
}
Run Code Online (Sandbox Code Playgroud)

另外,这更容易阅读:

if ($foo == 'bar' || $foo == 'baz' || $foo == 'bat' || $foo == 'buz') {
}
Run Code Online (Sandbox Code Playgroud)

要么

case 'bar':
case 'baz':
case 'bat':
case 'buz':
    break;
Run Code Online (Sandbox Code Playgroud)

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

去找你觉得最可读的方法.这是重要的部分.不要尝试微观优化.记住,Premature Optimization Is The Root Of All Evil......

  • @ ryabenko-pro,松散的比较会给你带来微妙的错误:`switch(0){case null:echo'null'; 打破; 默认值:echo'not null';}` (4认同)
  • 请注意,由于[松散的比较](http://stackoverflow.com/q/3525614/632951),此开关将给您**假**阴性和假阳性。在这里,“ switch”是代码气味和安全隐患。请改用数组键。 (2认同)