Deep understanding of the PHP array (traversal order) ____php

Source: Internet
Author: User

· Author: laruence (http://www.laruence.com/)
· This article address: http://www.laruence.com/2009/08/23/1065.html
· Reprint please indicate the source

People often ask me, PHP arrays, if you use foreach to access the order of traversal is fixed? In what order do you traverse it?
For example: <?php
$arr [' laruence '] = ' huixinchen ';
$arr [' yahoo '] = 2007;
$arr [' baidu '] = 2008;
foreach ($arr as $key => $val) {
What was the result?
}

Another example: <?php
$arr [2] = ' huixinchen ';
$arr [1] = 2007;
$arr [0] = 2008;
foreach ($arr as $key => $val) {
What's the result now?
}

To fully understand this problem, I think we should first understand the internal implementation structure of the PHP array ... an array of PHP

In PHP, arrays are implemented with a hash structure (HashTable), and PHP uses mechanisms that enable the addition and deletion of arrays in O (1) time complexity and support linear traversal and random access.

In the previous article also discussed, PHP hash algorithm, based on this, we do a further extension.

Before you know Hashtable, let's take a look at the structure definition of Hashtable, and I add comments to make it easy to understand: typedef struct _HASHTABLE {
uint ntablesize;    &NBS P  /* Hash list size, hash value interval * *
UINT ntablemask;       /* equals nTableSize-1, for quick positioning/
UINT NNu Number of actual elements in mofelements;   /* Hashtable * *
ULONG nnextfreeelement;/* Digital index of the next free available location/
Bucket * Pintern Alpointer;   /* Internal position pointers will be reset, current traversal functions using the/
Bucket * plisthead;     /* header elements, for linear Traversal/
Bucket * plisttail;     /* tail elements, for linear traversal/
Bucket * * arbuckets;     /* actual Storage container */
dtor_func_t pdestructor/* element destructor (pointer)/
Zend_bool persistent;
unsigned char napplycount; * Follow Loop traversal protection */
Zend_bool bapplyprotection
#if zend_debug
int inconsistent;
#endif
} HashTable;

As for the meaning of napplycount, we can use an example to understand: <?php
$arr = Array (1, 2, 3, 4, 5,);
$arr [] = & $arr;

Var_export ($arr); Fatal error:nesting level too deep-recursive dependency?

This field is created to prevent infinite loops caused by circular references.

Look at the structure above, as you can see, for Hashtable, the key element is Arbuckets, this is the actual storage container, let's look at its structure definition: typedef struct BUCKET {
ULong H;  & nbsp                     * Digital Index/hash value * *
UINT nkeylength;               /* Character index length * *
void * PData;            &NBS P      /* Data/
void * pdataptr;                  * Data pointer * *
struct bucket * plistnext;               /* next element for linear traversal/
Struc T bucket * plistlast;       /* previous element for linear traversal * *
struct bucket * pnext;      &NB Sp            /* The next element in the same zipper * *
struct bucket * pLast;        &NB Sp          /* The previous element in the same zipper/
char arkey [1];/* save memory, easy initialization skills/
Bucket

We note that the last element, this is the flexible array trick that can save memory, and facilitates initialization of an approach that interested friends can Google flexible array.

H is the hash value of the element, and for the element of the numeric index, h is the direct indexed value (the numeric index is represented by nkeylength=0). For numeric indexes, index values are saved in Arkey, and the length of the index is kept in nkeylength.

In bucket, the actual data is stored in a block of memory that the pdata pointer points to, usually the memory block is allocated separately by the system. One exception is that when bucket saves data as a pointer, Hashtable will not request the system to allocate space to save the pointer, but instead save the pointer directly to the PDATAPTR and then pdata to the address of the member of the structure. This can improve efficiency and reduce memory fragmentation. From this we can see the subtlety of the PHP hashtable design. If the data in bucket is not a pointer, pdataptr is null (This section comes from the Altair "Zend Hashtable detail")

Combining the above Hashtable structure, we explain the following Hashtable's summary composition:

Schematic diagram of hashtable structure

Hashtable's Plisthhead points to the first element in the linear list form, which is element 1, and plisttail points to the last element 0, and for each element plistnext is the next element of the linear structure drawn by the red line. And Plistlast is the last element.

Pinternalpointer points to the position of the current internal pointer, which indicates the current element when the array is sequentially traversed.

When the online sex (sequential) traversal, it will start from the Plisthead, along the bucket in the plistnext/plistlast, according to the mobile Pinternalpointer, to achieve the linear traversal of all the elements.

For foreach, for example, if we look at the opcode sequence it generates, we can see that before foreach, there will first be a fe_reset to reset the internal pointer of the array, which is pinternalpointer ( For foreach, see the deep understanding of the PHP principle foreach), and then through each fe_fetch to increment the pinternalpointer, so that the sequential traversal.

Similarly, when we use the Each/next series function to traverse, we also implement sequential traversal by moving the internal pointer of the array, there is a problem, for example: <?php
$arr = Array (1, 2, 3, 4, 5);
foreach ($arr as $v) {
Can get
}


while (the list ($key, $v) = each ($arr)) {
Not get the
}
?>

Knowing the knowledge I've just introduced, the question is clear, because foreach automatically reset, while this one doesn't reset, so after foreach ends, Pinternalpointer points to the end of the array, The while statement block is certainly inaccessible, and the solution is to reset the internal pointer of the array before each.

In random access, the hash value is used to determine the position of the head pointer in the hash array, and then the feature element is found by Pnext/plast.

When adding elements, the elements are inserted in the header of the same hash element chain and the tail of the linear list. That is, the elements are traversed in a linear traversal based on the sequence of inserts, and this particular design allows the sequence of elements to be determined in the order in which they are added, rather than in the order of the index, when using a numeric index in PHP.

That is, the sequence of the traversal of the array in PHP is related to the addition of elements, then, now we know very clearly, the beginning of the article the output of the problem is: Huixinchen
2007
2008

So if you want to iterate through the index size in an array of numeric indices, you should use for instead of foreach

for ($i = 0, $l = count ($arr); $i < $l; $i + +) {
This time, cannot be considered as sequential traversal (linear traversal)
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.