Deep understanding of the PHP array (traversal sequence) laruence original _php Tips

Source: Internet
Author: User
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?
Like what:
Copy Code code as follows:

<?php
$arr [' laruence '] = ' huixinchen ';
$arr [' yahoo '] = 2007;
$arr [' baidu '] = 2008;
foreach ($arr as $key => $val) {
What was the result?
}

Another example:
Copy Code code as follows:

<?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 a note to make it easier for everyone to understand:
Copy Code code as follows:

typedef struct _HASHTABLE {
UINT Ntablesize; /* Hash table size, the interval of the hash value * *
UINT Ntablemask; /* equals nTableSize-1, for quick positioning * *
UINT Nnumofelements; /* Number of actual elements in Hashtable * *
ULONG Nnextfreeelement; /* Digital Index for the next free available location * *
Bucket *pinternalpointer; /* Internal position pointer, will be reset, current these traversal functions using * *
Bucket *plisthead; /* header element, for linear traversal * *
Bucket *plisttail; /* tail element, for linear traversal * *
Bucket **arbuckets; /* The actual storage container * *
destructor (pointer) of dtor_func_t pdestructor;/* element
Zend_bool persistent;
unsigned char napplycount; /* Circular traversal protection * *
Zend_bool bapplyprotection;
#if Zend_debug
int inconsistent;
#endif
} HashTable;

With regard to the meaning of napplycount, we can use an example to understand:
Copy Code code as follows:

<?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.

Looking 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:
Copy Code code as follows:

typedef struct BUCKET {
ULONG H; /* Digital Index/hash Value * *
UINT Nkeylength; /* Character Index length * *
void *pdata; /* Data * *
void *pdataptr; /* Data pointer * *
struct bucket *plistnext; /* Next element, for linear traversal * *
struct bucket *plistlast; /* Previous element, for linear traversal * *
struct bucket *pnext; /* The next element in the same zipper * *
struct bucket *plast; /* The previous element in the same zipper * *
Char arkey[1]; /* Save memory, easy to initialize the skill * *
} 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 string indexing, 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:

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:
Copy Code code as follows:

<?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 order in which the arrays are traversed in PHP is related to the addition of the elements, so now we know very well that the output of the problem at the beginning of the article is:
Copy Code code as follows:

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
Copy Code code as follows:

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

Original: http://www.laruence.com/2009/08/23/1065.html

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.