Variables
Working with HashTable
Working with HashTable
Working with HashTable
The HashTable
structure
serves many purposes in PHP and can be found everywhere, a good
understanding of it’s functionality is a preqrequisite of being a
good Hacker
.
The HashTable
implemented
by the engine is a standard HashTable
,
that is to say, a key => value based store, where the keys are
always strings, whose hashes are calculated with a built in hashing
algorithm zend_inline_hash_func(const char* key,
, which results in good distribution, and
uint length)
reasonable usage.
The internal structure and exact operation of
HashTable
is out of the scope of this
document, this document serves to inform you of the API’s available
and how best to use them. For a more detailed picture of the
HashTable see Zend/zend_hash.h
.
Unless otherwise stated, these functions all return
FAILURE
if the requested operation fails
for any reason, otherwise SUCCESS
is
returned.
Note:
It is important to remember that ordinarily
HashTable
API functions expect key
lengths to be the length of the null terminated string, including
the null termination, in other words they expectstrlen(key) + 1
Below are some typedefs you should know when
interacting with HashTable
. They are
mostly self explanitory and will allow the Hacker
to fully understand the prototypes below
properly.
typedef ulong (*hash_func_t)(const char *arKey, uint nKeyLength); /* mostly redundant */ typedef int (*compare_func_t)(const void *, const void * TSRMLS_DC); /* comparison function */ typedef void (*sort_func_t)(void *, size_t, register size_t, compare_func_t TSRMLS_DC); /* sorting function */ typedef void (*dtor_func_t)(void *pDest); /* destructor function */ typedef void (*copy_ctor_func_t)(void *pElement); /* copy constructor */ typedef void (*copy_ctor_param_func_t)(void *pElement, void *pParam); /* copy with argument constructor */ typedef int (*apply_func_t)(void *pDest TSRMLS_DC); /* apply function */ typedef int (*apply_func_arg_t)(void *pDest, void *argument TSRMLS_DC); /* apply with argument function */ typedef int (*apply_func_args_t)(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key); /* apply with multiple arguments function */
int zend_hash_init(HashTable* ht, uint size, |
Initializes the hash table to hold at least size elements, hash existsfor historical reasons and is always ignored, zend_inline_hash_func is always used as the hashingfunction. destructor may be NULL . |
int zend_hash_add(HashTable* ht, const char* |
adds data to the table using thespecified key , where the key islength bytes long (and will be copiedfrom key to the table). If the key is setFAILURE will be returned. |
int zend_hash_update(HashTable* ht, const |
adds data to the table using thespecified key , where the key islength bytes long (and will be copiedfrom key to the table). If the key hasbeen set previously the old data has dtor_func_t called on it and the existing data isreplaced with data
|
int zend_hash_find(HashTable* ht, const |
searches the table for key , setting*data and returning SUCCESS if it isfound. |
zend_bool zend_hash_exists(HashTable* ht, |
returns positively if key is found inht
|
int zend_hash_del(HashTable* ht, const char* |
removes the entry identified by key from the table if found |
int zend_hash_index_update(HashTable* ht, |
updates the entry at index inht , with the data at data
|
int zend_hash_index_del(HashTable* ht, ulong |
deletes the entry at index fromht
|
int zend_hash_index_find(HashTable* ht, |
redirects *data to the dataidentified by index in ht
|
int zend_hash_index_exists(HashTable* ht, |
returns positively if index is foundin ht
|
ulong zend_hash_next_free_element(HashTable* |
returns the index of the next free element in ht
|
zend_hash_* functions that accept void* data
should normally cast it to (void**)
(ie, (void**)
)
&data
Traversing the HashTable is often necessary, to do
this you provide a pointer to a HashTable
, with an optional HashPosition
– a structure internal to the HashTable
API that allows traversal not to affect the internal position of
HashTable. The following traversal functions are provided, and an
example usage found below.
int |
resets the internal pointer of ht tothe start |
int |
sets position to the start ofht
|
int zend_hash_get_current_data(HashTable* |
gets the data at the current position in ht , data should be cast tovoid** , ie: (void**)
|
int zend_hash_get_current_data_ex(HashTable* |
sets data to the data at position in ht
|
int zend_hash_get_current_key(HashTable* ht, |
sets key , klen , and index from thekey information at the current position. The possible return values HASH_KEY_IS_STRING and HASH_KEY_IS_LONG are indicative of the kind of key found at the current posision. |
int zend_hash_get_current_key_ex(HashTable* |
sets key , klen , and index from thekey information at position . The possiblereturn values HASH_KEY_IS_STRING andHASH_KEY_IS_LONG are indicative of thekind of key found at position . |
int zend_hash_move_forward(HashTable* |
moves the internal pointer of ht tothe next entry in ht
|
int zend_hash_move_forward_ex(HashTable* ht, |
moves position to the next entry inht
|
The functions above allow traversal over a
HashTable
to be much like a normal loop,
which will look something like:
HashPosition position; zval **data = NULL; for (zend_hash_internal_pointer_reset_ex(ht, &position); zend_hash_get_current_data_ex(ht, (void**) &data, &position) == SUCCESS; zend_hash_move_forward_ex(ht, &position)) { /* by now we have data set and can use Z_ macros for accessing type and variable data */ char *key = NULL; uint klen; ulong index; if (zend_hash_get_current_key_ex(ht, &key, &klen, &index, 0, &position) == HASH_KEY_IS_STRING) { /* the key is a string, key and klen will be set */ } else { /* we assume the key to be long, index will be set */ } }
Note:
If a
HashTable
has been
passed into the engine, it is a good idea to use the zend_hash_*_ex
API to avoid unexpected behaviour in userland.
Note:
If a
duplicate
of the key
is requested andHAS_KEY_IS_STRING
is
returned the caller mustefree
the
duplicated key
In addition to traversal, the engine provides API
functions for merging, copying, and comparing HashTables. These are
all concepts that the Hacker
should be
familiar with. A concept possibly not in the repertoire of the
Hacker
is applying
, which is lamens terms is functionality of
the HashTable
API allowing the
Hacker
to pass a callback function to be
executed on every entry in a HashTable
.
void zend_hash_copy(HashTable *target, |
Copies the contents of source totarget . tmp should be an unallocated temporary pointer of the appropriate type, used during copying. size is the size ofeach element. |
void zend_hash_merge(HashTable *target, |
Merges the contents of source intodestination , replacing existing entriesonly where overwrite is true. |
void int zend_hash_sort(HashTable *ht, |
renumber controls if indexes shouldbe preserved, see the typedefs at the start of this section for more information |
Note:
When a function accepts a
copy_ctor_func_t pCopyConstructor
, the function
passed with be executed upon creation of every new entry in the
HashTable
. The most common copy
constructor used within the engine is a wrapper aroundzval_copy_ctor
, the macroZVAL_COPY_CTOR
.