On m'a souvent demandé, si l'éventail de PHP est accessible avec foreach, est l'ordre traversal fixe? Dans quel ordre? Par exemple, ?php$arr?????''''''''''''''''''''''''''''''$arr $arr''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'baidu'? - 2008; foreach ($arr
On me demande souvent, PHP tableau, si accessible par foreach, est l'ordre traversal fixe? Dans quel ordre ?
Comme quoi:
-
- $arr 'laruence') s 'huixinchen';
- $arr syahoo's 2007;
- $arr 'baidu') s 2008;
- foreach ($arr comme $key . . . . . . . . $val . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- Quel est le résultat ?
- }
par exemple:
-
- $arr 'huixinchen';
- $arr s1s s 2007;
- $arr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- foreach ($arr comme $key s. $val.
- Quel est le résultat maintenant?
- }
Pour bien comprendre ce problème, je pense que la première chose à faire est de comprendre la structure de mise en œuvre interne du tableau PHP ...
Array de PHP
Dans PHP, les tableaux sont implémentés à l'aide d'une structure HASH (HashTable), et PHP utilise des mécanismes qui permettent l'addition et la suppression du tableau à la complexité de temps de O(1), tout en soutenant à la fois l'accès linéaire et aléatoire.
Comme nous l'avons vu dans l'article précédent, l'algorithme HASH de PHP, basé sur cela, nous faisons une extension supplémentaire.
Avant d'apprendre à connaître HashTable, regardons la définition structurelle de HashTable, et j'ai ajouté un commentaire pour vous permettre de comprendre facilement:
typedef struct struct shtable . . .
uint nTableSize; /? intervalles de valeur de hh
uint nTableMask; /s égale nTableSize -1, pour un positionnement rapide
uint nNumOfElements; Nombre d'éléments réels dans hashTable
ulong nNextFreeElement; /? Index numérique pour le prochain emplacement disponible gratuit
Bucket spInternalPointer; /- Pointeur de position interne, sera réinitialisé, ces fonctions transversales sont utilisées par le
Seau spListHead; /?élément de tête, pour traversal linéaire
Seau spListTail; /-élément de queue, pour la traversée linéaire
Seau sarBuckets; /-Conteneurs de stockage réels.
dtor?func?t pDestructor;//le destructeur de l'élément (pointeur)
zend-bool persistant;
char non signé nApplyCount; /-Loop Traversal Protection
zend?bool bApplyProtection;
#if ZEND-DEBUG
inint inint;
#endif
HashTable;
Quant à l'importance de nApplyCount, nous pouvons apprendre à partir d'un exemple:
-
- $arr = array(1,2,3,4,5,);
- $arr[] = &$arr;
-
- var_export($arr); //Fatal error: Nesting level too deep - recursive dependency?
Ce champ est mis en place pour prévenir les boucles infinies causées par des références circulaires.
En regardant la structure ci-dessus, vous pouvez voir que pour HashTable, l'élément clé est arBuckets, c'est le conteneur de stockage réel, regardons sa définition structurelle:
seau de structuration de typedef
ulong h; /?indices numériques/valeurs hash
uint nLengthKey; La longueur de l'index de caractères /?
vide s pData; /s/ données
Void spDataPtr; /?pointeurs de données.
seau struct spListNext; /? Élément suivant, pour la traversée linéaire
seau struct spListLast; /? Élément précédent, pour la traversée linéaire
seau struct spNext; /? L'élément suivant dans la même fermeture éclair
seau struct spLast; /? L'élément précédent dans la même fermeture éclair
char arKey /-Mémoire-économie, conseils d'initialisation faciles
Un seau;
Nous notons que le dernier élément, c'est la technique de tableau flexible, qui peut enregistrer la mémoire et faciliter la initialisation dans une pratique où les amis intéressés peuvent google tableau flexible.
H est la valeur Hash de l'élément, pour l'élément de l'indice numérique, h est la valeur de l'indice direct (exprimé comme l'indice numérique par nKeyLength?0), et pour l'indice de chaîne, la valeur de l'indice est enregistrée dans arKey, la longueur de l'indice est enregistré dans nKeyLength.
Dans Bucket, les données réelles sont stockées dans un bloc de mémoire auquel le pointeur pData est généralement attribué séparément par le système. Dans un cas, cependant, lorsque Bucket enregistre des données qui est un pointeur, HashTable ne demandera pas au système d'allouer de l'espace pour tenir le pointeur, mais enregistrera le pointeur directement vers le pDataPtr, puis pointez le pData vers l'adresse du membre de la structure. Cela augmente l'efficacité et réduit la fragmentation de la mémoire. De là, nous pouvons voir les subtilités de la conception PHP HashTable. Si les données dans le seau ne sont pas un pointeur, pDataPtr est NULL (ce paragraphe de Altair "Zend HashTable Details")
Combiné avec la structure HashTable ci-dessus, nous allons illustrer la structure totale de HashTable ci-dessous:
Structure HashTable
Le pListhHead de HashTable indique le premier élément dans le formulaire de liste linéaire, qui est l'élément 1, les points pListTable au dernier élément 0, et pour chaque élément pListNext est l'élément suivant de la structure linéaire tracée par la ligne rouge, Et pListLast est le dernier élément.
PInternalPointer indique la position du pointeur interne actuel, qui indique l'élément actuel lors de la traversée du tableau de façon séquentielle.
Lorsque vous traversez linéairement (dans l'ordre), il commence par pListHead, en suivant le pListNext/pListLast dans Bucket, selon Mobile PInternalPointer, pour atteindre une traversée linéaire de tous les éléments.
Par exemple, pour foreach, si nous regardons la séquence opcode qu'il génère, nous pouvons voir qu'avant foreach, il y aura un FE-RESET pour réinitialiser le pointeur interne du tableau, c'est-à-dire pInternalPointer, puis à travers chaque FE FETCH pour incrémenter le pInternalPointer, afin d'atteindre la traversée séquentielle.
De même, lorsque nous utilisons la série de fonctions à traverser, nous mettons également en œuvre des traversées séquentielles en déplaçant les pointeurs internes du tableau, et voici un problème, par exemple :
-
- $arr tableau (1,2,3,4,5);
- foreach ($arr comme $v)
- Vous pouvez obtenir
- }
- tandis que (liste ($key, $v) s chacun ($arr))
- Impossible d'obtenir
- }
- ??
Sachant ce que je viens d'introduire, le problème est clair, parce que foreach sera automatiquement réinitialiser, et tandis que cette pièce ne sera pas réinitialiser, donc après la fin foreach, pInternalPointer points à la fin du tableau, Alors que les blocs de déclaration sont certainement inaccessibt, et la solution est de réinitialiser d'abord le pointeur interne du tableau avant chacun.
Lors de l'accès aléatoire, la position du pointeur de tête dans le tableau de hh est déterminée par la valeur de hh, puis l'élément de fonctionnalité est trouvé par pNext/pLast.
Lors de l'ajout d'éléments, des éléments sont insérés dans la tête de la même chaîne d'éléments de hayons et la queue de la liste linéaire. C'est-à-dire que les éléments traversent linéairement dans l'ordre d'insertion, et cette conception particulière permet dans PHP que lors de l'utilisation d'index numériques, l'ordre des éléments est déterminé par l'ordre dans lequel ils sont ajoutés, et non par l'ordre de l'indice.
C'est-à-dire, l'ordre de traverser les tableaux dans PHP est séquentiellement liée à l'ajout d'éléments, il est donc maintenant clair pour nous que la sortie du problème au début de l'article est:
huixinchen20072008
Donc, si vous voulez traverser par la taille de l'index dans un tableau d'index numériques, alors vous devriez utiliser pour, pas foreach.
pour ($i, 0, $l, count($arr); $i s/lt;$l; $i?
À l'heure actuelle, il ne peut pas être considéré comme une traversée séquentielle (traversée linéaire)
}