Skip to content

Instantly share code, notes, and snippets.

@Thinkscape
Created March 3, 2012 11:35
Show Gist options
  • Save Thinkscape/1965669 to your computer and use it in GitHub Desktop.
Save Thinkscape/1965669 to your computer and use it in GitHub Desktop.
A benchmark of several methods for checking if PHP array is associative
<?php
if(!isset($argv[1])){
echo "Usage: ".$argv[0]." (number of iterations)\n";
exit(1);
}
/**
* Arrays to check
*/
$tests = array(
array(array(
'foo' => 'bar',
)),
array(array(
'bar',
'foo' => 'bar',
'baz',
)),
array(null),
array(true),
array(false),
array(0),
array(1),
array(0.0),
array(1.0),
array('string'),
array(array(0, 1, 2)),
array(new stdClass),
array_fill(0,1000,uniqid()), // big numeric array
array_fill_keys(range(2,1000,3),uniqid()), // big misaligned numeric array (=associative)
array_fill_keys( // big associative array
str_split(
str_repeat(uniqid('',true),100),
3
),
true
)
);
$iterations = (int)$argv[1];
/**
* Common methods to check associative array
*/
$methods = array(
'method1 (array_values check)' =>
function($array){
return (array_values($array) !== $array);
},
'method2 (array_keys comparison)' =>
function($array){
$array = array_keys($array); return ($array !== array_keys($array));
},
'method3 (array_filter of keys)' =>
function($array){
return count(array_filter(array_keys($array), 'is_string')) > 0;
}
);
/**
* Perform benchmark on each method
*/
foreach($methods as $name=>$func){
echo "Testing $name - $iterations iterations\n";
$time = microtime(true);
for($x=0;$x<$iterations;$x++){
foreach($tests as $array){
$func($array);
}
}
/**
* Show results
*/
$totalTime = (microtime(true) - $time);
$avgTime = $totalTime / ($iterations * count($tests));
echo " Total time: ".number_format($totalTime,5,'.',' ')." s\n";
echo " Average : ".number_format($avgTime*1000,5,'.',' ')." ms / test \n";
echo "\n";
}
@ScorpioT1000
Copy link

ScorpioT1000 commented Aug 30, 2017

From PHPTester

PHP 5.5

Testing method1 (array_values check) - 10000 iterations
Total time: 0.85214 s
Average : 0.00568 ms / test

Testing method2 (array_keys comparison) - 10000 iterations
Total time: 1.57167 s
Average : 0.01048 ms / test

Testing method3 (array_filter of keys) - 10000 iterations
Total time: 2.99962 s
Average : 0.02000 ms / test

Testing method4 (foreach typecast) - 10000 iterations
Total time: 1.11735 s
Average : 0.00745 ms / test

PHP 5.6

Testing method1 (array_values check) - 10000 iterations
Total time: 1.00357 s
Average : 0.00669 ms / test

Testing method2 (array_keys comparison) - 10000 iterations
Total time: 1.77896 s
Average : 0.01186 ms / test

Testing method3 (array_filter of keys) - 10000 iterations
Total time: 3.71037 s
Average : 0.02474 ms / test

Testing method4 (foreach typecast) - 10000 iterations
Total time: 1.34244 s
Average : 0.00895 ms / test

PHP 7.0

Testing method1 (array_values check) - 10000 iterations
Total time: 0.23163 s
Average : 0.00154 ms / test

Testing method2 (array_keys comparison) - 10000 iterations
Total time: 0.30419 s
Average : 0.00203 ms / test

Testing method3 (array_filter of keys) - 10000 iterations
Total time: 0.60409 s
Average : 0.00403 ms / test

Testing method4 (foreach typecast) - 10000 iterations
Total time: 0.56797 s
Average : 0.00379 ms / test

@bpolaszek
Copy link

Method 1 is even more faster with PHP 7.2:

Testing method1 (array_values check) - 10000 iterations
Total time: 0.02857 s
Average : 0.00019 ms / test (!)

Testing method2 (array_keys comparison) - 10000 iterations
Total time: 0.19137 s
Average : 0.00128 ms / test

Testing method3 (array_filter of keys) - 10000 iterations
Total time: 0.48394 s
Average : 0.00323 ms / test

Testing method4 (foreach typecast) - 10000 iterations
Total time: 0.41342 s
Average : 0.00276 ms / test

@aminnairi
Copy link

Hi, I just came with an idea of a is_associative_array function if you are still open to contributions:

<?php

function is_associative_array( array &$a ): bool {

  $l = count( $a );

  for ( $i = 0; $i < $l; $i++ ) {
    if ( key( $a ) !== $i ) {
      return true;

    }

    next( $a );

  }

  return false;

}

Tell me about it!

@oriadam
Copy link

oriadam commented May 19, 2021

Hi, I just came with an idea of a is_associative_array function if you are still open to contributions:

<?php

function is_associative_array( array &$a ): bool {
  $l = count( $a );
  for ( $i = 0; $i < $l; $i++ ) {
    if ( key( $a ) !== $i ) {
      return true;
    }
    next( $a );
  }
  return false;
}

Tell me about it!

i just tested your method and it is way worse than all others... sorry :)

source: https://gist.github.com/oriadam/5e8424608fb3f8d70ec3e9ae344dbf8f

Testing 10000 iterations on PHP version 7.3.25

if (array_key_first($array)!==0) return true; return array_values($array) !== $array;
  Total time: 0.26179 s
  Average   : 0.00175 ms / test 

return array_values($array) !== $array;
  Total time: 0.23978 s
  Average   : 0.00160 ms / test 

return range(0,count($array)) !== array_keys($array);
  Total time: 0.44664 s
  Average   : 0.00298 ms / test 

return array_keys($array); return ($array !== array_keys($array));
  Total time: 0.50882 s
  Average   : 0.00339 ms / test 

return count(array_filter(array_keys($array), "is_string")) > 0;
  Total time: 3.99202 s
  Average   : 0.02661 ms / test 

foreach...$i++
  Total time: 1.23879 s
  Average   : 0.00826 ms / test 

for...key...next
  Total time: 7.73038 s
  Average   : 0.05154 ms / test 

@funder7
Copy link

funder7 commented Jan 15, 2022

check this out:

$methods = [
 
    // [...]

    'method4 (revision of method1, with php8.1 fn)' =>
       function ($array) {
            return (array_is_list($array) === false);
        },

    'method5 (json_encode output parsing with array_is_list - php>=8.1)' =>
       static function ($array) {
            // consider empty, and [0, 1, 2, ...] sequential
            if (empty($array) || array_is_list($array)) {
                return false;
            }

            // first scenario:
            // [  1  => [*any*] ]
            // [ 'a' => [*any*] ]
            foreach ( $array as $key => $value ) {
                if (is_array($value)) {
                    return true;
                }
            }

            // second scenario: read the json string
            $jsonNest = json_encode($array, JSON_THROW_ON_ERROR);

            return str_contains($jsonNest, '{');
        },


    'method6 (json_encode output parsing - php=8.0)' =>
       static function ($array) {

            if (empty($array) || array_values($array) !== $array) { return false; }

            foreach ( $array as $key => $value ) { if (is_array($value)) { return true; } }
            
            $jsonNest = json_encode($array, JSON_THROW_ON_ERROR);

            return str_contains($jsonNest, '{');
        },

];

Results

Testing method1 (array_values check) - 10000 iterations
  Total time: 0.60444 s
  Average   : 0.00403 ms / test 

Testing method2 (array_keys comparison) - 10000 iterations
  Total time: 0.32689 s
  Average   : 0.00218 ms / test 

Testing method3 (array_filter of keys) - 10000 iterations
  Total time: 2.22523 s
  Average   : 0.01483 ms / test 

Testing method4 (revision of method1, with php8.1 fn) - 10000 iterations
  Total time: 0.09834 s
  Average   : 0.00066 ms / test 

Testing method5 (json_encode output parsing with array_is_list - php>=8.1) - 10000 iterations
  Total time: 0.47469 s
  Average   : 0.00316 ms / test

Testing method6 (json_encode output parsing - php<=8.0) - 10000 iterations
  Total time: 1.01134 s
  Average   : 0.00674 ms / test 

Anyone curious about the benchmark without the static closure?

Testing method5 (json_encode output parsing with array_is_list - php>=8.1) - 10000 iterations
  Total time: 1.08914 s
  Average   : 0.00726 ms / test 

Testing method6 (json_encode output parsing - php=8.0) - 10000 iterations
  Total time: 4.92953 s
  Average   : 0.03286 ms / test 

They are much slower!

other methods perform the same instead. Somebody can explain me why?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment