views:

951

answers:

5

Is it faster to do the following:

 if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') { ... }

Or:

 if (!in_array($var, array('test1', 'test2', 'test3', 'test4') { ... }

Is there a number of values at which point it's faster to do one or the other?

(In this case, the array used in the second option doesn't alreay exist.)

+8  A: 

i'd strongly suggest just using in_array(), any speed difference would be negligible, but the readability of testing each variable separately is horrible.

just for fun here's a test i ran:

$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

slightly trivial note to watch for, if $var is not set, method 1 takes much longer (depending on how many conditions you test)

Owen
What version of PHP are you on? 5.2.6 (windows) gives Time1: 1.36Time2: 4.88 - that IS a big difference
Greg
Also you're cheating slightly by taking the array(...) out of the loop - if you use it as the question says, my time2 goes to over 6 seconds
Greg
5.2.5 (mac os x), i'm getting ~1.25 : ~4 with the non-cheating version
Owen
Can we assume that the question author would not stipulate the array be declared inline if he were running the code inside a tight loop?
Sparr
How is moving the array() initialization "cheating"? The loop is irrelevant to actual code. And if one assumes that the actual code in question may be executed many, many times, then of course, the OP would set a variable equal to the array of items he was searching first.
grantwparks
+2  A: 

The first will be faster - the second has a lot of overhead: creating the array, calling a function, searching the array...

However, as I said in a question a couple of answers down, premature optimization is the root of all evil. You should write your code to be readable, then if it needs to be optimized profile it, then optimize.

Edit:

My timings with @Owen's code (PHP 5.2.6 / windows):

Time1: 1.33601498604
Time2: 4.9349629879

Moving the array(...) inside the loop, as in the question:

Time1: 1.34736609459
Time2: 6.29464697838
Greg
bizarre :( should be someway to clear that
Owen
Oops, sorry for typo-ing your name Owen!
Greg
+2  A: 

in_array will be faster for large numbers of items. "large" being very subjective based on a lot of factors related to the data and your computer. Since you are asking, I assume you are not dealing with a trivial number of items. For longer lists, heed this information, and measure performance with a flipped array so that php can utilize hash lookups instead of a linear search. For a "static" array that tweak may not improve performance, but it also may.

Using Owen's test code, with a flipped array and more iterations for more consistent results:

$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
Sparr
Small comment: flipping a large array could use a lot of memory.
Darryl Hein
The array can be declared in the flipped configuration
Sparr
+3  A: 

Note that if you're looking to replace a bunch of !== statements, you should pass the third parameter to in_array as true, which enforces type checking on the items in the array.

Ordinary != doesn't require this, obviously.

Rob
+1  A: 

Note that as RoBorg pointed out, there's overhead in creating the array so it should be moved inside the iteration loop. For this reason, Sparr's post is also a little misleading as there's overhead with the array_flip function.

Here's another example with all 5 variations:

$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);

My results:

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

In summary, using array_flip (with isset) is faster than inarray but not as fast as a straight comparison.

Don't do the array flip in the loop. Change it to $array2 = array('test1'=>0,'test2'=>0,'test3'=>0,'test4'=>0); and try again. In the first case the array is constructed so in this case you should also construct the array.
jmucchiello
on the above comment, isset will return false on 0 as the val, better to use 1 as the val or use array_key_exists
Jason