Après avoir lu zend/zend_hash.h et ext/standard/array.c, je pense avoir trouvé la réponse (Merci à Chris et gumbo pour les suggestions).
Le tableau PHP est une table de hachage chaînée (recherche de O(c) et O(n) sur les collisions de clés) qui permet des clés de type int et string. Elle utilise deux algorithmes de hachage différents pour faire tenir les deux types de clés dans le même espace de hachage. De plus, chaque valeur stockée dans la table de hachage est liée à la valeur stockée avant et à la valeur stockée après (liste liée). Il possède également un pointeur temporaire qui est utilisé pour contenir l'élément actuel afin que le hachage puisse être itéré.
La prise pour le array_rand
est qu'afin de garantir que la clé est vraiment aléatoire, la fonction array_rand
doit itérer sur le tableau rand(0, count($array))
fois (O(n)). Ceci est dû au fait qu'il n'y a aucun moyen de se déplacer vers un décalage dans la table de hachage en temps O(c) car il n'y a aucune garantie qu'il n'y a pas de clés manquantes dans la plage.
Cette découverte m'a quelque peu troublé, car cela signifie qu'il n'existe AUCUN type de données en PHP qui ait les caractéristiques normales d'un tableau C. La plupart du temps, cela ne pose pas de problème, car les recherches par hachage sont plus rapides, mais ses défauts apparaissent dans les cas suivants array_rand
.
Une autre chose qui m'a également troublé est la différence entre l'implémentation de array_key_exists
y in_array
. array_key_exists
utilise la recherche de hachage (la plupart du temps O(c)) pour voir si une clé est dans le tableau, alors que in_array
doit rechercher linéairement le hachage (O(n)).
Considérez les deux exemples ci-dessous :
in_array version
$array = range(0, 100000);
if( in_array( $random_key, $array ) ) {
//we found a value
}
tableau_clé_existe version
$array = array_fill_keys( range(0, 100000), NULL );
if( array_key_exists( $random_key, $array ) ) {
//we found a value, err key
}
Bien que la version in_array semble beaucoup plus propre et plus simple à comprendre, elle est en fait très lente sur les grands tableaux (O(n)), alors que array_key_exists (malgré son nom fâcheusement long) est très rapide (O(c) ou presque).
En conclusion : J'aurais aimé qu'il y ait un drapeau transparent dans la structure de données de zend HashTable qui serait activé dans les cas où le tableau a été créé en utilisant array_push
o array[] = $value
qui permettrait une mise à l'échelle comme un tableau C au lieu d'une liste liée.
7 votes
Jetez un coup d'œil au code source : svn.php.net/viewvc/php/php-src/trunk/ext/spl/
0 votes
@Gumbo, lien vers le bas.....
2 votes
@Pacerier Voici le fichier dans le dépôt Github .