PHP extension development-array usage and HashTable Introduction

Source: Internet
Author: User

1 array This section describes php arrays. in php, arrays are implemented using HashTable. In this section, we will first introduce HashTable in detail, and then explain how to use HastTable1.1 the so-called variable length struct, which is actually a special usage of our C language struct, there is no novelty. Let's take a look at a general definition method of the Variable Length struct. Typedef struct bucket {int n; char key [30]; char value [1];} Bucket; we define a struct Bucket. We hope to use this struct to store the student's profile. The key is used to store the student's name, and the value is used to store the student's profile. You may be curious. Our value declares how much information can be stored in 1. 1 char? In fact, for variable-length struct, we cannot directly define variables in use, for example, Bucket bucket. If you use them like this, the value certainly cannot store much information. For a variable-length struct, We need to declare a pointer to the variable-length struct before allocating the function space through the malloc function. What is the length of the space we need, we can use malloc. The general usage method is as follows: Bucket * pBucket; pBucket = malloc (sizeof (Bucket) + n * sizeof (char); where n is the length of the value you want to use. If this is used, will the string pointed to by value become longer soon! 1.2 introduction to Hashtable let's take a look at the definition of HashTable struct _ hashtable; typedef struct bucket {ulong h; // use uint nKeyLength when the element is a digital index; // when using string indexes, this variable indicates the index length. The index (string) is saved in the last element aKey void * pData; // It is used to point to the stored data. If the stored data is a pointer, pDataPtr points to this data, and pData points to pDataPtr void * pDataPtr; struct bucket * pListNext; // The last element struct bucket * pListLast; // The next element struct bucket * pNext; // The pointer to the next bucket, struct bucket * pLast; // the pointer to the previous bucket, char arKey [1]; // It must be placed at the end, mainly to implement a variable-length struct} Bucket; typedef struct _ hashtable {uint nTableSize; // the size of the hash table uint nTableMask; // The value is equal to nTableSize-1 uint nNumOfElements; // records the number of records saved in the current HashTable ulong nNextFreeElement; // points to the next idle Bucket * pInternalPointer; // This variable is used as an array to reverse the Bucket * pListHead; // point to the Bucket's header Bucket * pListTail; // point to the Bucket's end Bucket ** arBuckets; dtor_func_t pDestructor; // function pointer, it is automatically called during addition, deletion, modification, and query of arrays for some cleaning operations zend_bool. Persistent; // whether to persistently unsigned char nApplyCount; zend_bool bApplyProtection; // works with nApplyCount to prevent infinite recursion of array traversal # if ZEND_DEBUG int inconsistent; # endif} HashTable; I hope you can take a good look at the above definition. I will not understand some things when I come out. It is better to see the code clearly. PHP arrays are actually two-way linked lists with header nodes. HashTable is the header, and the Bucket stores the specific node information. 1.3 HashTable internal function analysis 1.3.1 macro HASH_PROTECT_RECURSION # defineHASH_PROTECT_RECURSION (ht) \ if (ht)-> bApplyProtection) {\ if (ht)-> nApplyCount ++> = 3) {\ zend_error (E_ERROR, "Nestinglevel too deep-recursive dependency? ") ;\}\} This macro is mainly used to prevent circular references. 1.3.2 macro ZEND_HASH_IF_FULL_DO_RESIZE # convert (ht) \ if (ht)-> nNumOfElements> (ht)-> nTableSize) {\ zend_hash_do_resize (ht ); \} the macro is used to check whether the number of elements in HashTable is greater than the total size of HashTable. If the number is greater than the size of HashTable, we will re-allocate the space. Let's take a look at zend_hash_do_resizestatic int zend_hash_do_resize (HashTable * ht) {Bucket ** t; IS_CONSISTENT (ht); if (ht-> nTableSize <1)> 0) {/* Let's double the table size */t = (Bucket **) perealloc_recoverable (ht-> arBuckets, (ht-> nTableSize <1) * sizeof (Bucket *), ht-> persistent); if (t) {HANDLE_BLOCK_INTERRUPTIONS (); ht-> arBuckets = t; ht-> nTableSize = (ht-> nTableSize <1); ht-> nTableMask = ht-> nTa BleSize-1; zend_hash_rehash (ht); HANDLE_UNBLOCK_INTERRUPTIONS (); return SUCCESS;} return FAILURE;} return SUCCESS;} as we can see from the code above, when HashTable allocates space, the allocated space is twice the original space. 1.3.3 function _ initialize is used to initialize HashTable. Let's take a look at the code: ZEND_API int _ zend_hash_init (HashTable * ht, uint nSize, hash_func_t pHashFunction, extends pDestructor, zend_bool persistent) {uint I = 3; // by default, the size of HashTable does not have the 3rd-power Bucket ** tmp; SET_INCONSISTENT (HT_ OK); if (nSize> = 0x80000000) {ht-> nTableSize = 0x80000000;} else {while (1U <I) <nSize) {I ++;} ht-> nTableSize = 1 <I;} Ht-> nTableMask = ht-> nTableSize-1; ht-> pDestructor = pDestructor; ht-> arBuckets = NULL; ht-> pListHead = NULL; ht-> pListTail = NULL; ht-> nNumOfElements = 0; ht-> nNextFreeElement = 0; ht-> pInternalPointer = NULL; ht-> persistent = persistent; ht-> nApplyCount = 0; ht-> bApplyProtection = 1;/* Uses ecalloc () so that Bucket * = NULL */if (persistent) {tmp = (Bucket **) calloc (ht-> nTableSize, sizeo F (Bucket *); if (! Tmp) {return FAILURE;} ht-> arBuckets = tmp;} else {tmp = (Bucket **) ecalloc_rel (ht-> nTableSize, sizeof (Bucket *)); if (tmp) {ht-> arBuckets = tmp;} return SUCCESS;} we can see that the HashTable size is initialized to the Npower of 2. In addition, we can see two memory modes, one is calloc and the other is ecalloc_rel. We have discussed the memory allocation methods in detail. If you are interested, you can check them by yourself. 1.3.4 function _ detail this function adds or modifies the Element Information ZEND_API int _ zend_hash_add_or_update (HashTable * ht, const char * arKey, uint nKeyLength, void * pData, uint nDataSize, void ** pDest, int flag ZEND_FILE_LINE_DC) {ulong h; uint nIndex; Bucket * p; IS_CONSISTENT (ht); if (nKeyLength <= 0) {# if ZEND_DEBUG ZEND_PUTS ("zend_hash_update: Can't put inempty key \ n"); # endif return FAILURE;} h = zend_inlin E_hash_func (arKey, nKeyLength); nIndex = h & ht-> nTableMask; p = ht-> arBuckets [nIndex]; while (p! = NULL) {if (p-> h = h) & (p-> nKeyLength = nKeyLength) {if (! Memcmp (p-> arKey, arKey, nKeyLength) {if (flag & HASH_ADD) {return FAILURE;} HANDLE_BLOCK_INTERRUPTIONS (); # if ZEND_DEBUG if (p-> pData = pData) {ZEND_PUTS ("Fatal error in zend_hash_update: p-> pData = pData \ n"); HANDLE_UNBLOCK_INTERRUPTIONS (); return FAILURE ;}# endif if (ht-> pDestructor) {ht-> pDestructor (p-> pData);} UPDATE_DATA (ht, p, pData, nDataSize ); if (pDest) {* pDest = p-> pData;} HANDLE _ UNBLOCK_INTERRUPTIONS (); return SUCCESS ;}} p = p-> pNext;} p = (Bucket *) pemalloc (sizeof (Bucket)-1 + nKeyLength, ht-> persistent); if (! P) {return FAILURE;} memcpy (p-> arKey, arKey, nKeyLength); p-> nKeyLength = nKeyLength; INIT_DATA (ht, p, pData, nDataSize ); p-> h = h; CONNECT_TO_BUCKET_DLLIST (p, ht-> arBuckets [nIndex]); if (pDest) {* pDest = p-> pData;} HANDLE_BLOCK_INTERRUPTIONS (); CONNECT_TO_GLOBAL_DLLIST (p, ht); ht-> arBuckets [nIndex] = p; HANDLE_UNBLOCK_INTERRUPTIONS (); ht-> nNumOfElements ++; Combine (ht);/* I F the Hash table is full, resize it */return SUCCESS;} 1.3.5 macro CONNECT_TO_BUCKET_DLLIST # define CONNECT_TO_BUCKET_DLLIST (element, list_head) \ (element)-> pNext = (list_head ); \ (element)-> pLast = NULL; \ if (element)-> pNext) {\ (element)-> pNext-> pLast = (element ); \} This macro is used to add a bucket to the bucket linked list. For other functions or macro definitions, we will just briefly introduce HashTable. If you want to learn more about HashTable, we recommend that you check the php source code. The HashTable code can be found in Zend/zend_hash.h and Zend/zend _ In hash. c. The handler adds an empty element to the function. Based on the index deletion element, the handler reversely traverses the iterator copy _ zend_hash_merge and merges zend_hash_find string indexes to find the zend_hash_index_find numeric index method. The two functions in the Handler are encapsulated zend _ whether zend_hash_index_exists has the index zend_hash_quick_exists. The encapsulation of the two methods above is 1.4 C extension. The commonly used HashTable function although HashTable looks a bit complicated, however, it is very convenient to use. We can use the following function to initialize and assign values to HashTable. In 2005, the number of local students enrolled in the PHP syntax C syntax meaning $ arr = array () array_init (arr); Initialization array $ arr [] = NULL; add_next_index_null (arr ); $ arr [] = 42; add_next_index_long (arr, 42); $ arr [] = true; add_next_index_bool (arr, 1); $ arr [] = 3.14; add_next_index_double (3.14 ); $ arr [] = 'foo'; add_next_index_string (arr, "foo", 1); 1 means copying strings $ arr [] = $ myvar; add_next_index_zval (arr, myvar); $ arr [0] = NULL; add_index_null (arr, 0); $ arr [1] = 42; add_index _ Long (arr, 1, 42); $ arr [2] = true; add_index_bool (arr, 2, 1); $ arr [3] = 3.14; add_index_double (arr, 3, 3, 14); $ arr [4] = 'foo'; add_index_string (arr, 4, "foo", 1); $ arr [5] = $ myvar; add_index_zval (arr, 5, myvar); $ arr ["abc"] = NULL; add_assoc_null (arr, "abc"); $ arr ["def"] = 711; add_assoc_long (arr, "def", 711); $ arr ["ghi"] = true; add_assoc_bool (arr, ghi ", 1); $ arr [" jkl "] = 1.44; add_assoc_double (arr, "jkl", 1.44); $ arr ["mno"] = 'baz'; add_assoc_string (arr, "mno", "baz", 1 ); $ arr ['pqr '] = $ myvar; add_assoc_zval (arr, "pqr", myvar); 1.5 the number of tasks and experiments has been discussed. Let's experiment. Task: returns an Array with the following data: Array ([0] => for test [42] => 123 [for test. for test.] => 1 [array] => Array ([0] => 3.34) code implementation: PHP_FUNCTION (test) {zval * t; array_init (return_value); add_next_index_string (return_value, & quot; for test & quot;, 1); add_index_long (return_value, 42,123); add_assoc_double (return_value, & quot; for test. for test. ", 1.0); ALLOC_INIT_ZVAL (t); array_init (t); add_next_index_double (t, 3.34); add_assoc _ Zval (return_value, "array", t);} is simple. Do you still remember return_value?

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.