Hash table is collection. It is specialized form of doubly linked list. As it’s heavily used in zend engine and PHP Core, so therefore an entire subset of API is devoted to it.
Hash table is important because
- All upper space variable are stored in hash table.
- Hash table can store any piece of data of any size
General syntax for initializing hash table is
zend_hash_init(HashTable *ht, uint nSize,
hash_func_t pHashFunction,
dtor_func_t pDestructor, zend_bool persistent);
Here
ht is pointer to HashTable variable.
nSize is maximum number of elements that HashTable is expected to hold. It will always be power of 2.
pHashFunction is no longer used in new versions, so it must always be NULL.
pDestructor is pointer to function that is called whenever an element is removed such as when using zend_hash_del or zend_hash_update.
The prototype of the destructor must be
void method_name(void *pElement)
Where pElement is pointer to the element to be removed.
The final option, persistent is flag passed by zend engine to the pemalloc() function.
An example of initializing the hash table can be
zend_hash_init(&EG(symbol_tabel), 50, NULL, ZVAL_PTR_DTOR, 0);
Populating the hash table
The following functions are used to populate HashTable.
- int zend_hash_add(HashTable *ht, char *arrKey, uinit nKeySize, void *pData, uinit nDataSize, void **pDest)
- int zend_hash_update(HashTable *ht, char *arrKey, uinit nKeySize, void *pData, uinit nDataSize, void **pDest)
- int zend_hash_index_update(HashTable *ht, ulong h, void *pDate, uinit nDataSize, void **pDest)
- int zend_hash_next_index_insert(HashTable *ht, void *pData, uinit nDataSize, void **pDest)
Let’s have a look at some examples
If you want to represent $foo[“bar”] = “baz”; write
zval barValue;
MAKE_STD_ZVAL(barValue);
Z_TYPE_P(barValue) = IS_STRING;
Z_STRVAL_P(barValue) = “baz”;
S_STRLEN_P(barValue) = sizeof(‘baz’) + 1
zend_hash_add(fooHashTable, “bar”, sizeof(“bar”), &barValue, sizeof(zval *), NULL);
Some time you will need to find the free element before performing insert, update etc on the Zend table. In this case you can get the next free element by writing
ulong nextid = zend_hash_next_free_element(ht);
and now perform update as
zend_hash_upate(ht, nextid, &data, sizeof(data), NULL)
Finding data in HashTable
In the above paragraphs I discuss how to initialize and populate HashTable, Here I’d discuss how to find particular key/index value in the HashTable
Two methods are used.
One if you want to find value of particular key in case of associative array. The syntax as
int zend_hash_find(HashTable *ht, char *key, uint nKeySize, void **pData);
And the other function is used to find value at specified index in case of indexed array.
The general syntax of the method is
int zend_hash_find(HashTable *ht, ulong index, void **pData);
Another very important functionality Hash API provide is to check whether or not the specified key or index exists. Two method are used for this purpose.
zend_hash_exists(HashTable *ht, char *key, unit nKeySize);
This method is used to check the key in case of associative array.
While
zend_hash_exists(HashTabel *ht, ulong index);
The upper space function for checking the key is
isset($foo);
To achieve this using Hash API, use
zend_hash_exists(EG(active_symbol_table), “foo”, sizeof(“foo”));
This function will return true or false.
Iterating through HashTable
Hash API provides some useful functions for iterating through hash table.
- zend_hash_apply(HashTable *ht, (apply_func_t) apply func TSRMLS_DC);
- zend_hash_apply_with_argument(HashTable *ht, (apply_func_arg_t) apply_func void *data TSRLMS_DC);
- zend_hash_apply_with_arguments(HashTable *ht, (apply_func_args_t) apply_func, int numargs, …)
Each of the apply_func_t return the following
- ZEND_HASH_APPLY_KEEP
- ZEND_HASH_APPLY_STOP
- ZEND_HASH_APPLY_REMOVE
Beside these functions there are some other useful functions for working with HashTables.
Try these functions as well
- zend_get_hash_value(char *arrKey, uint nKeyLen);
- zend_hash_quick_add(HashTable *ht, char *arKey, uint nKeyLen, ulong hashval void *pData, uint nDataSize, void **pDest);
- zend_hash_quick_update(HashTable *ht, char *arKey, uint nKeyLen, ulong hashval void *pData, uint nDataSize, void **pDest);
- zend_hash_find(HashTable *ht, char *arKey, uint nKeyLen, ulong hashval, void **pDest)
- zend_hash_quick_exists(HashTable *ht, char *arKey, uint nKeyLen, ulong hashval);
Destruction
There four method you need to keep in mind while removing element(s) from HashTable.
- zend_hash_del(HashTable *ht, char *nKey, uint nKeySize);
- zend_hash_index_del(HashTable *ht, ulong h)
- zend_hash_clean(HashTable *ht)
- zend_hash_destroy(HashTable *ht)
The first two method remove single element from the HashTable.
zend_hash_clean iterate through each element and clean the entire hash table.
zend_hash_destroy all the function of zend_hash_clean plus free the structure allocated during zend_hash_init.
While working with the hash table, you may need the following as well
HashTable *ht;
// allocate memory
ALLOC_HASHTABLE(ht);
// initialize it internal state
zend_hash_init(ht, 50, NULL, ZVAL_PTR_DTOR, 0);
// destroy the hash table
zend_hash_destroy(ht);
// free the hash table itself
FREE_HASHTABLE(ht);