Php extension and embedding-array and Hash Table 2 in php extension

Source: Internet
Author: User
Tags php foreach
Next, let's talk about the APIs of arrays and hash tables in the php extension. this section mainly describes the sorting, comparison, and pole & amp; 20540 of callback traversal functions; the IterationbyhashApply function is used to traverse the array. The simplest is to use an api that follows the preceding section with ph to continue with the array and hash table in the php extension, this section mainly describes the sorting, comparison, and extreme value functions of the normal Traversal function of the callback Traversal function.

Iteration by hash Apply:The simplest way to traverse an array is to use a function similar to the foreach statement function in php. zend_hash_apply receives a callback function and passes each element of hashtable to it.
typedef int (*apply_func_t)(void *pDest TSRMLS_DC);void zend_hash_apply(HashTable *ht,        apply_func_t apply_func TSRMLS_DC);
typedef int (*apply_func_arg_t)(void *pDest,                            void *argument TSRMLS_DC);void zend_hash_apply_with_argument(HashTable *ht,        apply_func_arg_t apply_func, void *data TSRMLS_DC);
One can pass parameters, and the other can only pass values in the hash table without passing parameters. For functions that can pass parameters, it is more likely to be applied in extensions. The callback function may return different values:
Return value of the table callback function
Constant Meaning
ZEND_HASH_APPLY_KEEP ends the current request and enters the next loop. It works the same way as a forech statement in PHP when a loop is completed or the continue keyword is encountered.
ZEND_HASH_APPLY_STOP jumps out, which is the same as the break keyword in the forech statement of PHP language.
ZEND_HASH_APPLY_REMOVE deletes the current element and continues to process the next element. Equivalent to: unset ($ foo [$ key]); continue;

For a simple php traversal code
 
The extension format is as follows: first define the callback function
Int php_sample_print_zval (zval ** val TSRMLS_DC) {// copy a zval again to prevent damage to the original data zval tmpcopy = ** val; zval_copy_ctor (& tmpcopy ); // convert to The string INIT_PZVAL (& tmpcopy); convert_to_string (& tmpcopy); // Start to output php_printf ("The value is:"); PHPWRITE (Z_STRVAL (tmpcopy ), z_STRLEN (tmpcopy); php_printf ("\ n"); // destroy zval_dtor (& tmpcopy); // return, continue traversing the next ~ Return ZEND_HASH_APPLY_KEEP ;}
Then define the cyclic function: zend_hash_apply (arrht, php_sample_print_zval TSRMLS_CC );
A hash table named arrht whose element type is zval * is traversed.
Note that the hashed table is not an element, but a pointer, that is, a zval **. it Also copies the pointer during replication, and the hash table itself does not change the content.

To receive both the value and the key during the loop, the third form zend_hash_apply (): zend_hash_apply_with_arguments ()
  $val) {     echo "The value of $key is: $val\n"; }?>
C code for this php code:
Int php_sample_print_zval_and_key (zval ** val, int num_args, va_list args, zend_hash_key * hash_key) {/* copy zval to save the original content */zval tmpcopy = ** val; /* tsrm_ls is needed by output functions */ctor (); zval_copy_ctor (& tmpcopy);/* Reset refcount & Convert */INIT_PZVAL (& tmpcopy); convert_to_string (& tmpcopy ); /* output */php_printf ("The value of"); if (hash_key-> nKeyLength) {/* if it is a string key */PHPWRITE (hash_key-> arKey, hash_key-> nKeyLength);} else {/* if it is a digital key */php_printf ("% ld", hash_key-> h);} php_printf ("is: "); PHPWRITE (Z_STRVAL (tmpcopy), Z_STRLEN (tmpcopy); php_printf (" \ n ");/* Toss out old copy */zval_dtor (& tmpcopy ); /* continue; */return ZEND_HASH_APPLY_KEEP ;}

Execute traversal: zend_hash_apply_with_arguments (arrht, php_sample_print_zval_and_key, 0). when we check whether the hash_key is a string or a number, it is detected by the nKeyLength attribute, not the arKey attribute. This is because the kernel sometimes keeps some dirty data in the arKey attribute, but the nKeyLength attribute is secure and can be safely used. It can even process null string indexes. For example, $ foo [''] =" Bar "; the index value is a NULL character, but its length includes the last NULL character, so it is 1.

Iteration by move forwardHash table traversal can be implemented without calling back. In this case, the internal pointer of the hash table is used.
There are many available functions in the user space:
 1, 'b'=>2, 'c'=>3);    reset($arr);    while (list($key, $val) = each($arr)) {        /* Do something with $key and $val */    }    reset($arr);    $firstkey = key($arr);    $firstval = current($arr);    $bval = next($arr);    $cval = next($arr);?>
Each corresponding function has a zend version:
* /* reset() */void zend_hash_internal_pointer_reset(HashTable *ht);        /* key() */int zend_hash_get_current_key(HashTable *ht,        char **strIdx, unit *strIdxLen,        ulong *numIdx, zend_bool duplicate);* /* current() */int zend_hash_get_current_data(HashTable *ht, void **pData);* /* next()/each() */int zend_hash_move_forward(HashTable *ht);* /* prev() */int zend_hash_move_backwards(HashTable *ht);* /* end() */void zend_hash_internal_pointer_end(HashTable *ht);* /* Other... */int zend_hash_get_current_key_type(HashTable *ht);int zend_hash_has_more_elements(HashTable *ht);
Next () prev () end () is to find the corresponding index value, and then use zend_hash_get_current_data () to return the element value.
Each () is the same as the next step, but calls and returns zend_hash_get_current_key ()

So the following provides a hash table traversal method without callback functions:
Void php_sample_print_var_hash (HashTable * arrht) {for (arrht); round (arrht) = SUCCESS; round (arrht) {char * key; uint keylen; ulong idx; int type; zval ** ppzval, tmpcopy; type = zend_hash_get_current_key_ex (arrht, & key, & keylen, & idx, 0, NULL); // obtain the type of the returned key. This type may have three if (zend_hash_get_current_data (arrht, (void **) & ppzval) = FAILURE) {// obtain the data value specified by the current index/* shocould never actually fail * since the key is known to exist. */continue;}/* copy the zval value, so that the original value will not be damaged */tmpcopy = ** ppzval; zval_copy_ctor (& tmpcopy ); /* reset refcount and convert */INIT_PZVAL (& tmpcopy); convert_to_string (& tmpcopy);/* output */php_printf ("The value "); if (type = HASH_KEY_IS_STRING) {/* String Key/Associative */PHPWRITE (key, keylen);} else {/* Numeric Key */php_printf ("% ld ", idx);} php_printf ("is:"); PHPWRITE (Z_STRVAL (tmpcopy), Z_STRLEN (tmpcopy); php_printf ("\ n "); /* destroy the original copy */zval_dtor (& tmpcopy );}}
Let's take a look at the possibility that zend_hash_get_current_key_ex will return a value: Constant Meaning

The index of the current element of HASH_KEY_IS_STRING is of the string type. Therefore, a pointer to the element's key name will be populated into strIdx, and its length will be populated into stdIdxLen. if the duplicate flag is set to a nonzero value, the key will be estrndup () 'd before being populated into strIdx. the calling application is expected to free this duplicated string.

The index of the current element of HASH_KEY_IS_LONG is numeric.
The internal pointer in HASH_KEY_NON_EXISTANT HashTable has been moved to the end without pointing to any element.


DestructionNote that there are only four destructor: the first two are used to delete a single element from the hash table:
int zend_hash_del(HashTable *ht, char *arKey, uint nKeyLen);int zend_hash_index_del(HashTable *ht, ulong h);
Return SUCCESS OR FAILURE
Corresponding to the version of string and numeric index respectively.
When an element is removed from a hash table, the destructor of the hash table is called with a pointer pointing to this element.

When the hash table is completely deleted: void zend_hash_clean (HashTable * ht); equivalent to calling zend_hash_del cyclically. In addition to executing clean, call the following function to get all the space applied for by zend_hash_init: void zend_hash_destroy (HashTable * ht );
We can have a clearer understanding of the entire process by looking at the lifecycle of a hash table:
Int sample_strvec_handler (int argc, char ** argv TSRMLS_DC) {HashTable * ht;/* allocate space for the hash table */ALLOC_HASHTABLE (ht ); /* initialize the internal state of the hash table */if (zend_hash_init (ht, argc, NULL, ZVAL_PTR_DTOR, 0) = FAILURE) {FREE_HASHTABLE (ht); return FAILURE ;} /* change each string to zval **/while (argc) {zval * value; MAKE_STD_ZVAL (value); ZVAL_STRING (value, argv [argc], 1); argv ++; if (zend_hash_next_index_insert (ht, (void **) & value, sizeof (zval *) = FAILURE) {/* skip */zval_ptr_dtor (& value) ;}/ * Do some work */process_hashtable (ht) if the allocation fails ); /* destroy the hash table * release all allocated spaces */zend_hash_destroy (ht);/* Free the HashTable itself */FREE_HASHTABLE (ht); return SUCCESS ;}


Sorting, Comparing, and Going to the Extreme (s)Compare the sizes of two hash tables: typedef int (* compare_func_t) (void * a, void * B TSRMLS_DC); this function is the same as qsort, we look forward to comparing a and B with your own functions, and return-1 0 1.

The following is an example of comparing the data size:
int zend_hash_minmax(HashTable *ht, compare_func_t compar,                        int flag, void **pData TSRMLS_DC);
If the flag is 0, the minimum value is returned. Otherwise, the maximum value is returned.

The following is a more specific example. different flags can be used to determine whether to return the maximum or minimum values:
int fname_compare(zend_function *a, zend_function *b TSRMLS_DC){    return strcasecmp(a->common.function_name, b->common.function_name);}void php_sample_funcname_sort(TSRMLS_D){    zend_function *fe;    if (zend_hash_minmax(EG(function_table), fname_compare,                0, (void **)&fe) == SUCCESS) {        php_printf("Min function: %s\n", fe->common.function_name);    }    if (zend_hash_minmax(EG(function_table), fname_compare,                1, (void **)&fe) == SUCCESS) {        php_printf("Max function: %s\n", fe->common.function_name);    }}

There is also a hash comparison function: int zend_hash_compare (HashTable * hta, HashTable * htb,
Compare_func_t compar, zend_bool ordered TSRMLS_DC); first, compare the number of hash tables. If there are as many elements, compare them with each element.

There is also a special sorting function:
typedef void (*sort_func_t)(void **Buckets, size_t numBuckets,            size_t sizBucket, compare_func_t comp TSRMLS_DC);int zend_hash_sort(HashTable *ht, sort_func_t sort_func,        compare_func_t compare_func, int renumber TSRMLS_DC);
Generally, it is enough to use zend_qsort as sort_func. If the renumber parameter is set to 1, the original index key-value relationship is discarded and a new number key value is assigned. Aggregate (target_hash, zend_qsort, array_data_compare, 1 TSRMLS_CC); array_data_compare is a function that returns compare_func_t data, sorted by the zval * Value in HashTable.


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.