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 algorythim zend_inline_hash_func(const char* key, uint length), which results in good distribution, and 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 opeation fails for any reason, otherwise SUCCESS is returned.

注意:

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 expect strlen(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.

Initializes the hash table to hold at least size elements, hash exists for historical reasons and is always ignored, zend_inline_hash_func is always used as the hashing function. destructor may be NULL.

adds data to the table using the specified key, where the key is length bytes long (and will be copied from key to the table). If the key has been set previously the old data has dtor_func_t called on it and the existing data is replaced with 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.

sets key, klen, and index from the key 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.

sets key, klen, and index from the key information at position. The possible return values HASH_KEY_IS_STRING and HASH_KEY_IS_LONG are indicative of the kind of key found at position.

int zend_hash_move_forward(HashTable* ht)

moves the internal pointer of ht to the next entry in ht

int zend_hash_move_forward_ex(HashTable* ht, HashPosition position)

moves position to the next entry in ht

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 */
}
}

注意:

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.

注意:

If a duplicate of the key is requested and HAS_KEY_IS_STRING is returned the caller must efree 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.

renumber controls if indexes should be preserved, see the typedefs at the start of this section for more information

注意:

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 around zval_copy_ctor, the macro ZVAL_COPY_CTOR.