执行以下操作是否更快:
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') { ... }
或者:
if (!in_array($var, array('test1', 'test2', 'test3', 'test4') { ... }
是否有许多值,在这一点上做一个或另一个更快?
(在这种情况下,第二个选项中使用的数组并不存在。)
执行以下操作是否更快:
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') { ... }
或者:
if (!in_array($var, array('test1', 'test2', 'test3', 'test4') { ... }
是否有许多值,在这一点上做一个或另一个更快?
(在这种情况下,第二个选项中使用的数组并不存在。)
我强烈建议只使用in_array()
,任何速度差异都可以忽略不计,但是单独测试每个变量的可读性是可怕的。
只是为了好玩,这是我运行的一个测试:
$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
$end = microtime(true);
print "Time1: ". ($end - $start)."<br />";
$start2 = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, $array) ) {}
}
$end2 = microtime(true);
print "Time2: ".($end2 - $start2)."<br />";
// Time1: 1.12536692619
// Time2: 1.57462596893
需要注意的一点微不足道的注意事项,如果$var
未设置,方法 1 需要更长的时间(取决于您测试的条件数)
Martijn:我已经将数组扩展为五个元素,并寻找test3
,作为一种平均情况。
PHP5.6
Time1: 0.20484399795532
Time2: 0.29854393005371
PHP7.1
Time1: 0.064045906066895
Time2: 0.056781053543091
PHP7.4
Time1: 0.048759937286377
Time2: 0.049691915512085
PHP8.0
Time1: 0.045055150985718
Time2: 0.049431085586548
结论:原始测试不是最好的测试,而且:在 php7+ 中已成为偏好问题。
请注意,如果您要替换一堆!==
语句,则应将第三个参数传递给in_array
as true
,这会强制对数组中的项目进行类型检查。
普通!=
的显然不需要这个。
第一个会更快 - 第二个有很多开销:创建数组,调用函数,搜索数组......
然而,正如我在几个答案中所说的那样,过早优化是万恶之源。您应该编写可读的代码,然后如果需要对其进行优化,则对其进行优化。
编辑:
我对@Owen 的代码(PHP 5.2.6 / windows)的时间安排:
Time1: 1.33601498604
Time2: 4.9349629879
在循环内移动数组(...),如问题所示:
Time1: 1.34736609459
Time2: 6.29464697838
这是该板凳的实时更新与另一个案例https://3v4l.org/OA2S7
PHP 7.3 的结果:
多重比较:0.0575 07991790771
in_array: 0.0256 8507194519
array_flip() 外循环测量 + isset(): 0.0146 78001403809
array_flip() 外部循环未测量 + isset(): 0.0156 50033950806
foreach 和比较:0.0627 82049179077
嗨,我只是将这种情况发挥到了极致,并指出随着值数量的增加,简单的比较并不是最有效的方式。
这是我的代码:
$var = 'test';
$num_values = 1000;
$iterations = 1000000;
print "\nComparison performance test with ".$num_values." values and ".$iterations." loop iterations";
print "\n";
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if ($var != 'test0' &&
$var != 'test1' &&
// ...
// yes I really have 1000 lines in my file
// ...
$var != 'test999') {}
}
print "\nCase 1: plain comparison";
print "\nTime 1: ". (microtime(true) - $start);
print "\n";
$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
$array1[] = 'test'.$i;
}
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, $array1) ) {}
}
print "\nCase 2: in_array comparison";
print "\nTime 2: ".(microtime(true) - $start);
print "\n";
$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
$array2['test'.$i] = 1;
}
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array2[$var])) {}
}
print "\nCase 3: values as keys, isset comparison";
print "\nTime 3: ".(microtime(true) - $start);
print "\n";
$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
$array3['test'.$i] = 1;
}
for($i = 0; $i < $iterations; ++$i) {
if (!array_key_exists($var, $array3)) {}
}
print "\nCase 4: values as keys, array_key_exists comparison";
print "\nTime 4: ".(microtime(true) - $start);
print "\n";
我的结果(PHP 5.5.9):
Case 1: plain comparison
Time 1: 31.616894006729
Case 2: in_array comparison
Time 2: 23.226133823395
Case 3: values as keys, isset comparison
Time 3: 0.050863981246948
Case 4: values as keys, array_key_exists comparison
Time 4: 0.13700890541077
我同意,这有点极端,但它展示了 PHP 的类哈希表关联数组的大局和巨大潜力,你只需要使用它
in_array 对于大量项目会更快。基于与数据和您的计算机相关的许多因素,“大”是非常主观的。既然您在问,我假设您处理的项目数量并不多。对于较长的列表,请注意此信息,并使用翻转数组来衡量性能,以便 php 可以利用散列查找而不是线性搜索。对于“静态”数组,调整可能不会提高性能,但也可能。
使用 Owen 的测试代码,使用翻转数组和更多迭代以获得更一致的结果:
$array2 = array_flip($array);
$iterations = 10000000;
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array2[$var])) {}
}
$end = microtime(true);
print "Time3: ".($end - $start)."<br />";
Time1: 12.875
Time2: 13.7037701607
Time3: 3.70514011383
请注意,正如 RoBorg 指出的那样,创建数组有开销,因此应该在迭代循环内移动它。出于这个原因,Sparr 的帖子也有点误导,因为 array_flip 函数存在开销。
这是另一个包含所有 5 种变体的示例:
$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
print "Time1: ". (microtime(true) - $start);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, $array) ) {}
}
print "Time2: ".(microtime(true) - $start);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, array('test1', 'test2', 'test3', 'test4')) ) {}
}
print "Time2a: ".(microtime(true) - $start);
$array2 = array_flip($array);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array2[$var])) {}
}
print "Time3: ".(microtime(true) - $start);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
$array2 = array_flip($array);
if (!isset($array2[$var])) {}
}
print "Time3a: ".(microtime(true) - $start);
我的结果:
Time1 : 0.59490108493 // straight comparison
Time2 : 0.83790588378 // array() outside loop - not accurate
Time2a: 2.16737604141 // array() inside loop
Time3 : 0.16908097267 // array_flip outside loop - not accurate
Time3a: 1.57209014893 // array_flip inside loop
总之,使用array_flip
(with isset) 比 inarray 快,但不如直接比较快。
当谈到 PHP,并询问是否:
更好,
应该记住,PHP 语言“switch”语句是为这种情况设计的替代方法,可能是更好的答案。(虽然张贴者的例子让我们只比较两个解决方案,但实际的问题标题要求考虑 in_array 与 PHP 语句,所以我认为这是公平的游戏)。
那么,在海报的示例中,我建议:
switch ($var)
{ case 'test1': case 'test2': case 'test3': case 'test4':
echo "We have a good value"; break;
default:
echo "We do not have a good value";
}
我希望 PHP 在这种情况下允许使用几个非原始构造,例如“或”的逗号。但是上面是 PHP 的设计者认为是处理这个问题的最清晰的方法。而且它在执行时似乎也比其他两种选择更有效。
只要我说的是愿望清单,在 SQL 中找到的“IN”对于发布者的示例情况会更加清晰。
这种想法可能是导致人们想要在这种情况下使用“in_array”的原因,但不幸的是必须构建一个数据结构,然后使用为该数据结构设计的谓词,而不是有办法只在没有发生这种开销的情况下说出来。
我知道这个问题已经有将近 10 年的历史了,但是还有其他方法可以做到这一点。我使用了Nick 页面中的方法 B,其中包含数千个条目。它非常快。
foreach(array_values($haystack) as $v)
$new_haystack[$v] = 1;
}
// So haystack becomes:
$arr[“String1”] = 1;
$arr[“String2”] = 1;
$arr[“String3”] = 1;
// Then check for the key:
if (isset($haystack[$needle])) {
echo("needle ".$needle." found in haystack");
}
我的测试
$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
$end = microtime(true);
print "Time1: ". ($end - $start)."<br />";
$start2 = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, $array) ) {}
}
$end2 = microtime(true);
print "Time2: ".($end2 - $start2)."<br />";
$array_flip = array_flip($array);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array_flip[$var])) {}
}
$end = microtime(true);
print "Time3: ".($end - $start)."<br />";
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array[$var])) {}
}
$end = microtime(true);
print "Time4: ". ($end - $start)."<br />";
时间1:0.20001101493835
时间2:0.32601881027222
时间3:0.072004079818726
时间4:0.070003986358643