Sophie

Sophie

distrib > Mageia > 4 > x86_64 > by-pkgid > f800694edefe91adea2624f711a41a2d > files > 8451

php-manual-en-5.5.7-1.mga4.noarch.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>Working with HashTable</title>

 </head>
 <body><div class="manualnavbar" style="text-align: center;">
 <div class="prev" style="text-align: left; float: left;"><a href="internals2.variables.arrays.html">Working with Arrays</a></div>
 <div class="next" style="text-align: right; float: right;"><a href="internals2.variables.objects.html">Working with Objects</a></div>
 <div class="up"><a href="internals2.variables.html">Working with Variables</a></div>
 <div class="home"><a href="index.html">PHP Manual</a></div>
</div><hr /><div id="internals2.variables.tables" class="section">
  <h2 class="title">Working with HashTable</h2>
  
  <p class="para">The <code class="code">HashTable</code> structure serves many purposes in PHP and can be found everywhere, a good understanding of it&#039;s functionality is a preqrequisite of being a good <code class="code">Hacker</code>.</p>
  
  <p class="para">The <code class="code">HashTable</code> implemented by the engine is a standard <code class="code">HashTable</code>, that is to say, a key =&gt; value based store, where the keys are always strings, whose hashes are calculated with a built in hashing algorithm <code class="code">zend_inline_hash_func(const char* key, uint length)</code>, which results in good distribution, and reasonable usage.</p>
  
  <p class="para">The internal structure and exact operation of <code class="code">HashTable</code> is out of the scope of this document, this document serves to inform you of the API&#039;s available and how best to use them. For a more detailed picture of the HashTable see <code class="code">Zend/zend_hash.h</code>.</p>
  
  <p class="para">Unless otherwise stated, these functions all return <code class="code">FAILURE</code> if the requested opeation fails for any reason, otherwise <code class="code">SUCCESS</code> is returned.</p>
  
  <blockquote class="note"><p><strong class="note">Note</strong>: 
   <p class="para">It is important to remember that ordinarily <code class="code">HashTable</code> API functions expect key lengths to be the length of the null terminated string, including the null termination, in other words they expect <code class="code">strlen(key) + 1</code></p>
  </p></blockquote>
  
  <p class="para">Below are some typedefs you should know when interacting with <code class="code">HashTable</code>. They are mostly self explanitory and will allow the <code class="code">Hacker</code> to fully understand the prototypes below properly.</p>
  
  <div class="example-contents screen">
<div class="cdata"><pre>
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 */
</pre></div>
  </div>
  
  <table id="internals2.variables.advrrays.api" class="doctable table">
   <caption><strong>HashTable API</strong></caption>
   
    <tbody class="tbody">
     <tr>
      <td><code class="code">int zend_hash_init(HashTable* ht, uint size, hash_func_t hash, dtor_func_t destructor, zend_bool persistent)</code></td>
     </tr>

     
     <tr>
      <td>Initializes the hash table to hold at least <code class="code">size</code> elements, <code class="code">hash</code> exists for historical reasons and is always ignored, <code class="code">zend_inline_hash_func</code> is always used as the hashing function. <code class="code">destructor</code> may be <code class="code">NULL</code>.</td>
     </tr>

     
     <tr>
      <td><code class="code">int zend_hash_add(HashTable* ht, const char* key, uint klen, void* data, uint dlen, void** dest)</code></td>
     </tr>

     
     <tr>
      <td>adds <code class="code">data</code> to the table using the specified <code class="code">key</code>, where the key  is <code class="code">length</code> bytes long (and will be copied from <code class="code">key</code> to the table). If the key is set FAILURE will be returned.</td>
     </tr>

     
     <tr>
      <td><code class="code">int zend_hash_update(HashTable* ht, const char* key, uint klen, void* data, uint dlen, void** dest)</code></td>
     </tr>

     
     <tr>
      <td>adds <code class="code">data</code> to the table using the specified <code class="code">key</code>, where the key  is <code class="code">length</code> bytes long (and will be copied from <code class="code">key</code> to the table). If the key has been set previously the old data has <code class="code">dtor_func_t</code> called on it and the existing data is replaced with <code class="code">data</code></td>
     </tr>

     
     <tr>
      <td><code class="code">int zend_hash_find(HashTable* ht, const char* key, uint klen, void** data)</code></td>
     </tr>

     
     <tr>
      <td>searches the table for <code class="code">key</code>, setting <code class="code">*data</code> and returning SUCCESS if it is found.</td>
     </tr>

     
     <tr>
      <td><code class="code">zend_bool zend_hash_exists(HashTable* ht, const char* key, uint klen)</code></td>
     </tr>

     
     <tr>
      <td>returns positively if <code class="code">key</code> is found in <code class="code">ht</code></td>
     </tr>

     
     <tr>
      <td><code class="code">int zend_hash_del(HashTable* ht, const char* key, uint klen)</code></td> 
     </tr>

     
     <tr>
      <td>removes the entry identified by <code class="code">key</code> from the table if found</td>
     </tr>

     
     <tr>
      <td><code class="code">int zend_hash_index_update(HashTable* ht, ulong index, void* data, uint dsize, void** dest)</code></td>
     </tr>

     
     <tr>
      <td>updates the entry at <code class="code">index</code> in <code class="code">ht</code>, with the data at <code class="code">data</code></td>
     </tr>

     
     <tr>
      <td><code class="code">int zend_hash_index_del(HashTable* ht, ulong index)</code></td>
     </tr>

     
     <tr>
      <td>deletes the entry at <code class="code">index</code> from <code class="code">ht</code></td>
     </tr>

     
     <tr>
      <td><code class="code">int zend_hash_index_find(HashTable* ht, ulong index, void** data)</code></td>
     </tr>

     
     <tr>
      <td>redirects <code class="code">*data</code> to the data identified by <code class="code">index</code> in <code class="code">ht</code></td>
     </tr>

     
     <tr>
      <td><code class="code">int zend_hash_index_exists(HashTable* ht, ulong index)</code></td>
     </tr>

     
     <tr>
      <td>returns positively if <code class="code">index</code> is found in <code class="code">ht</code></td>
     </tr>

     
     <tr>
      <td><code class="code">ulong zend_hash_next_free_element(HashTable* ht)</code></td>
     </tr>

     
     <tr>
      <td>returns the index of the next free element in <code class="code">ht</code></td>
     </tr>

     
    </tbody>
   
  </table>

  
  <div class="caution"><strong class="caution">Caution</strong>
   <p class="para">zend_hash_* functions that accept <code class="code">void* data</code> should normally cast it to <code class="code">(void**)</code> (ie, <code class="code">(void**) &amp;data</code>)</p>
  </div>
  
  <p class="para">Traversing the HashTable is often necessary, to do this you provide a pointer to a <code class="code">HashTable</code>, with an optional <code class="code">HashPosition</code> - 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.</p>
  
  <table id="internals2.variables.trarrays.api" class="doctable table">
   <caption><strong>HashTable Traversal API</strong></caption>
   
    <tbody class="tbody">
     <tr>
      <td><code class="code">int zend_hash_internal_pointer_reset(HashTable* ht)</code></td>
     </tr>

     <tr>
      <td>resets the internal pointer of <code class="code">ht</code> to the start</td>
     </tr>

     <tr>
      <td><code class="code">int zend_hash_internal_pointer_reset_ex(HashTable* ht, HashPosition position)</code></td>
     </tr>

     <tr>
      <td>sets <code class="code">position</code> the the start of <code class="code">ht</code></td>
     </tr>

     <tr>
      <td><code class="code">int zend_hash_get_current_data(HashTable* ht, void* data)</code></td>
     </tr>

     <tr>
      <td>gets the data at the current position in <code class="code">ht</code>, <code class="code">data</code> should be cast to <code class="code">void**</code>, ie: <code class="code">(void**) &amp;data</code></td>
     </tr>

     <tr>
      <td><code class="code">int zend_hash_get_current_data_ex(HashTable* ht, void* data, HashPosition position)</code></td>
     </tr>

     <tr>
      <td>sets <code class="code">data</code> to the data at <code class="code">position</code> in <code class="code">ht</code></td>
     </tr>

     <tr>
      <td><code class="code">int zend_hash_get_current_key(HashTable* ht, void* data, char**key, uint klen, ulong index, zend_bool duplicate)</code></td>
     </tr>

     <tr>
      <td>sets <code class="code">key</code>, <code class="code">klen</code>, and <code class="code">index</code> 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.</td>
     </tr>

     <tr>
      <td><code class="code">int zend_hash_get_current_key_ex(HashTable* ht, void* data, char**key, uint klen, ulong index, zend_bool duplicate, HashPosition position)</code></td>
     </tr>

     <tr>
      <td>sets <code class="code">key</code>, <code class="code">klen</code>, and <code class="code">index</code> from the key information at <code class="code">position</code>. The possible return values <code class="code">HASH_KEY_IS_STRING</code> and <code class="code">HASH_KEY_IS_LONG</code> are indicative of the kind of key found at <code class="code">position</code>.</td>
     </tr>

     <tr>
      <td><code class="code">int zend_hash_move_forward(HashTable* ht)</code></td>
     </tr>

     <tr>
      <td>moves the internal pointer of <code class="code">ht</code> to the next entry in <code class="code">ht</code></td>
     </tr>

     <tr>
      <td><code class="code">int zend_hash_move_forward_ex(HashTable* ht, HashPosition position)</code></td>
     </tr>

     <tr>
      <td>moves <code class="code">position</code> to the next entry in <code class="code">ht</code> </td>
     </tr>

    </tbody>
   
  </table>

  
  <p class="para">The functions above allow traversal over a <code class="code">HashTable</code> to be much like a normal loop, which will look something like:</p>
  
  <div class="example-contents screen">
<div class="cdata"><pre>
HashPosition position;
zval **data = NULL;

for (zend_hash_internal_pointer_reset_ex(ht, &amp;position);
     zend_hash_get_current_data_ex(ht, (void**) &amp;data, &amp;position) == SUCCESS;
     zend_hash_move_forward_ex(ht, &amp;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, &amp;key, &amp;klen, &amp;index, 0, &amp;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 */
     }
}
</pre></div>
  </div>
  
  <blockquote class="note"><p><strong class="note">Note</strong>: 
   <p class="para">If a <code class="code">HashTable</code> has been passed into the engine, it is a good idea to use the zend_hash_*_ex API to avoid unexpected behaviour in userland.</p>
  </p></blockquote>
  
  <blockquote class="note"><p><strong class="note">Note</strong>: 
   <p class="para">If a <code class="code">duplicate</code> of the key is requested and <code class="code">HAS_KEY_IS_STRING</code> is returned the caller must <code class="code">efree</code> the duplicated key</p>
  </p></blockquote>
  
  <p class="para">In addition to traversal, the engine provides API functions for merging, copying, and comparing HashTables. These are all concepts that the <code class="code">Hacker</code> should be familiar with. A concept possibly not in the repertoire of the <code class="code">Hacker</code> is <code class="code">applying</code>, which is lamens terms is functionality of the <code class="code">HashTable</code> API allowing the <code class="code">Hacker</code> to pass a callback function to be executed on every entry in a <code class="code">HashTable</code>.</p>
  
  <table id="internals2.variables.coparrays.api" class="doctable table">
   <caption><strong>Copying, Merging and Sorting</strong></caption>
   
    <tbody class="tbody">
     <tr>
      <td><code class="code">void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size)</code></td>
     </tr>

     
     <tr>
      <td>Copies the contents of <code class="code">source</code> to <code class="code">target</code>. <code class="code">tmp</code> should be an unallocated temporary pointer of the appropriate type, used during copying. <code class="code">size</code> is the size of each element.</td>
     </tr>

     
     <tr>
      <td><code class="code">void zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, zend_bool overwrite)</code></td>
     </tr>

     
     <tr>
      <td>Merges the contents of <code class="code">source</code> into <code class="code">destination</code>, replacing existing entries only where <code class="code">overwrite</code> is true.</td>
     </tr>

     
     <tr>
      <td><code class="code">void int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compare_func, int renumber TSRMLS_DC)</code></td>
     </tr>

     
     <tr>
      <td><code class="code">renumber</code> controls if indexes should be preserved, see the typedefs at the start of this section for more information</td>
     </tr>

     
    </tbody>
   
  </table>

  
  <blockquote class="note"><p><strong class="note">Note</strong>: 
   <p class="para">When a function accepts a <code class="code">copy_ctor_func_t pCopyConstructor</code>, the function passed with be executed upon creation of every new entry in the <code class="code">HashTable</code>. The most common copy constructor used within the engine is a wrapper around <code class="code">zval_copy_ctor</code>, the macro <code class="code">ZVAL_COPY_CTOR</code>.
   </p>
  </p></blockquote>
  
 </div><hr /><div class="manualnavbar" style="text-align: center;">
 <div class="prev" style="text-align: left; float: left;"><a href="internals2.variables.arrays.html">Working with Arrays</a></div>
 <div class="next" style="text-align: right; float: right;"><a href="internals2.variables.objects.html">Working with Objects</a></div>
 <div class="up"><a href="internals2.variables.html">Working with Variables</a></div>
 <div class="home"><a href="index.html">PHP Manual</a></div>
</div></body></html>