The Speed of Various Existential PHP Functions

You want to right a pretty existential function in PHP so you can do things like the following without throwing warnings (warnings that write to disc, or the screen, slow things down and burn platters).

If $ar[1][2][3] is not set then a warning is thrown.

Examples of Places You Should Use Existential Calls

if(42 == $ar[1][2][3]){
  echo "We have the Answer!";
}
 
some_func($ar[1][2][3]);

Here are some timed tests of existential functions. The most common is
the ternary isset.

Ternary Existential Calls (ugly)

if(42 == (isset($ar[1][2][3])) ? $ar[1][2][3] : False){
   echo "We have the Answer!";
}

But i find that syntax ugly, i would like to do something more cogent, with out all the extra ? and : in the if‘s predicate. I have created a function isgd stands for “Is Set Get” This would be nicer, but it comes at a speed cost.

An Existential Function Call

if(42 == isg($ar,1,2,3)){
  echo "We Have The Answer!";
}
 
// Or you might want to call a function with a default value
// if $ar[1][2][3] is not set:
 
 
some_func(isgd($ar,"Don't Panic!",1,2,3));

Here are a list of 5 solutions for the existential crisis, I have a speed summary as well as an explanation/guideline below.

An Existential Speed Tests

 
$iters = 1e5;
 
$ar[5][5][5][5][5] = 5;
 
$tic = microtime(true);
for($ii=0; $ii<$iters; $ii++){
  $val = @$ar[5][5][5][5][5];
}
$toc = microtime(true);
$elapsed_time = round($toc - $tic,2);
echo "Elapsed Time Using @ $elapsed_time seconds\n";
 
$tic = microtime(true);
for($ii=0; $ii<$iters; $ii++){
  $val = isg($ar,5,5,5,5,5);
}
$toc = microtime(true);
$elapsed_time = round($toc - $tic,2);
echo "Elapsed Time Using isg $elapsed_time seconds\n";
 
$tic = microtime(true);
for($ii=0; $ii<$iters; $ii++){
  $val = isgd($ar,NULL,5,5,5,5,5);
}
$toc = microtime(true);
$elapsed_time = round($toc - $tic,2);
echo "Elapsed Time Using isgd $elapsed_time seconds\n";
 
 
$tic = microtime(true);
for($ii=0; $ii<$iters; $ii++){
  $val = (isset($ar[5][5][5][5][5])) ? $ar[5][5][5][5][5] : False;
}
$toc = microtime(true);
$elapsed_time = round($toc - $tic,2);
echo "Elapsed Time Using Terinary $elapsed_time seconds\n";
 
$tic = microtime(true);
for($ii=0; $ii<$iters; $ii++){
  $val = array_multi_key_exists(Array(5,5,5,5,5),$ar);
}
$toc = microtime(true);
$elapsed_time = round($toc - $tic,2);
echo "Elapsed Time Using array_multi_key_exists $elapsed_time seconds\n";
 
$tic = microtime(true);
for($ii=0; $ii<$iters; $ii++){
  $val = eval_iff($ar,5,5,5,5,5);
}
$toc = microtime(true);
$elapsed_time = round($toc - $tic,2);
echo "Elapsed Time Using eval_iff $elapsed_time seconds\n";
 
 
 
// From php.net/array_key_exists
function array_multi_key_exists(array $arrNeedles, array $arrHaystack, $blnMatchAll=true){
    $blnFound = array_key_exists(array_shift($arrNeedles), $arrHaystack);
 
    if($blnFound && (count($arrNeedles) == 0 || !$blnMatchAll))
        return true;
 
    if(!$blnFound && count($arrNeedles) == 0 || $blnMatchAll)
        return false;
 
    return array_multi_key_exists($arrNeedles, $arrHaystack, $blnMatchAll);
}
 
// is set get
function isg($ar){
  $val = $ar;
  for($ii = 1; $ii < func_num_args(); $ii++){
    $arg = func_get_arg($ii);
    if(!isset($val[$arg])){
      return NULL;
    }
    $val = $val[$arg];
  }
  return $val;
}
 
// is set get with a defualt
function isgd($ar,$default){
  $val = $ar;
  for($ii = 2; $ii < func_num_args(); $ii++){
    $arg = func_get_arg($ii);
    if(!isset($val[$arg])){
      return NULL;
    }
    $val = $val[$arg];
  }
  return $default;
}
 
 
// Not safe and very slow
function eval_iff($ar){
  $val = $ar;
  $to_eval = '$ar';
 
  for($ii = 1; $ii < func_num_args(); $ii++){
    $arg = func_get_arg($ii);
    $to_eval .= "[$arg]";
  }
  eval('$val = (isset(' . $to_eval . ')) ? ' . $to_eval . ' : NULL;');
  return $val;
}
 
 
/*
Running PHP 5.3
 
Results for 10000 iterations.
Elapsed Time Using @ 0.13 seconds
Elapsed Time Using isg 0.5 seconds
Elapsed Time Using isgd 0.51 seconds
Elapsed Time Using Terinary 0.07 seconds
Elapsed Time Using array_multi_key_exists 0.44 seconds
Elapsed Time Using eval_iff 2.71 seconds
 
*/

Summary : ? is the fastest, but is bulky. isg is slower than @ with little benefit. Ternary is the fastest and allows default, but also pretty ugly inside of code. Ugly code takes a long time to debug so only use Ternary when all that maters is super-fast code. array_multi_key_exists and isg are both slower than @ but because there is not default there is little benefit. eval_iff is just bad all around.

So if you don’t need a default and NULL is OK, then use @. If you do need a default and you don’t need the particular check to be very fast (like its only called a handful of times) then use isgd. If must be really fast so being ugly doesn’t matter use the Ternary.

Share
This entry was posted in beginner-programming. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

If you are going to post code please use:
<pre lang="php" escaped="true"> YOUR_CODE_HERE </pre>

Change the lang to mysql, python, lisp, whatever. This will escape your code.