PHP Extensions: Understanding and working with hash API Part 1

10 May

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

  1. All upper space variable are stored in hash table.
  2. 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.

  1. int zend_hash_add(HashTable *ht, char *arrKey, uinit nKeySize, void *pData, uinit nDataSize, void **pDest)
  2. int zend_hash_update(HashTable *ht, char *arrKey, uinit nKeySize, void *pData, uinit nDataSize, void **pDest)
  3. int zend_hash_index_update(HashTable *ht, ulong h, void *pDate, uinit nDataSize, void **pDest)
  4. 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.

  1. zend_hash_apply(HashTable *ht, (apply_func_t) apply func TSRMLS_DC);
  2. zend_hash_apply_with_argument(HashTable *ht, (apply_func_arg_t) apply_func void *data TSRLMS_DC);
  3. zend_hash_apply_with_arguments(HashTable *ht, (apply_func_args_t) apply_func, int numargs, …)

Each of the apply_func_t return the following

  1. ZEND_HASH_APPLY_KEEP
  2. ZEND_HASH_APPLY_STOP
  3. ZEND_HASH_APPLY_REMOVE

Beside these functions there are some other useful functions for working with HashTables.

Try these functions as well

  1. zend_get_hash_value(char *arrKey, uint nKeyLen);
  2. zend_hash_quick_add(HashTable *ht, char *arKey, uint nKeyLen, ulong hashval void *pData, uint nDataSize, void **pDest);
  3. zend_hash_quick_update(HashTable *ht, char *arKey, uint nKeyLen, ulong hashval void *pData, uint nDataSize, void **pDest);
  4. zend_hash_find(HashTable *ht, char *arKey, uint nKeyLen, ulong hashval, void **pDest)
  5. 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.

  1. zend_hash_del(HashTable *ht, char *nKey, uint nKeySize);
  2. zend_hash_index_del(HashTable *ht, ulong h)
  3. zend_hash_clean(HashTable *ht)
  4. 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);

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: