PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - spl - spl_observer.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 398
Code covered: 95.2 % Executed lines: 379
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 6                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is SplSubject to version 3.01 of the PHP license,   |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Marcus Boerger <helly@php.net>                              |
      16                 :    |          Etienne Kneuss <colder@php.net>                             |
      17                 :    +----------------------------------------------------------------------+
      18                 :  */
      19                 : 
      20                 : /* $Id: spl_observer.c 289250 2009-10-06 13:34:56Z colder $ */
      21                 : 
      22                 : #ifdef HAVE_CONFIG_H
      23                 : # include "config.h"
      24                 : #endif
      25                 : 
      26                 : #include "php.h"
      27                 : #include "php_ini.h"
      28                 : #include "ext/standard/info.h"
      29                 : #include "ext/standard/php_var.h"
      30                 : #include "ext/standard/php_smart_str.h"
      31                 : #include "zend_interfaces.h"
      32                 : #include "zend_exceptions.h"
      33                 : 
      34                 : #include "php_spl.h"
      35                 : #include "spl_functions.h"
      36                 : #include "spl_engine.h"
      37                 : #include "spl_observer.h"
      38                 : #include "spl_iterators.h"
      39                 : #include "spl_array.h"
      40                 : #include "spl_exceptions.h"
      41                 : 
      42                 : SPL_METHOD(SplObserver, update);
      43                 : SPL_METHOD(SplSubject, attach);
      44                 : SPL_METHOD(SplSubject, detach);
      45                 : SPL_METHOD(SplSubject, notify);
      46                 : 
      47                 : ZEND_BEGIN_ARG_INFO(arginfo_SplObserver_update, 0)
      48                 :         ZEND_ARG_OBJ_INFO(0, SplSubject, SplSubject, 0)
      49                 : ZEND_END_ARG_INFO();
      50                 : 
      51                 : static const zend_function_entry spl_funcs_SplObserver[] = {
      52                 :         SPL_ABSTRACT_ME(SplObserver, update,   arginfo_SplObserver_update)
      53                 :         {NULL, NULL, NULL}
      54                 : };
      55                 : 
      56                 : ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_attach, 0)
      57                 :         ZEND_ARG_OBJ_INFO(0, SplObserver, SplObserver, 0)
      58                 : ZEND_END_ARG_INFO();
      59                 : 
      60                 : ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_void, 0)
      61                 : ZEND_END_ARG_INFO();
      62                 : 
      63                 : /*ZEND_BEGIN_ARG_INFO_EX(arginfo_SplSubject_notify, 0, 0, 1)
      64                 :         ZEND_ARG_OBJ_INFO(0, ignore, SplObserver, 1)
      65                 : ZEND_END_ARG_INFO();*/
      66                 : 
      67                 : static const zend_function_entry spl_funcs_SplSubject[] = {
      68                 :         SPL_ABSTRACT_ME(SplSubject,  attach,   arginfo_SplSubject_attach)
      69                 :         SPL_ABSTRACT_ME(SplSubject,  detach,   arginfo_SplSubject_attach)
      70                 :         SPL_ABSTRACT_ME(SplSubject,  notify,   arginfo_SplSubject_void)
      71                 :         {NULL, NULL, NULL}
      72                 : };
      73                 : 
      74                 : PHPAPI zend_class_entry     *spl_ce_SplObserver;
      75                 : PHPAPI zend_class_entry     *spl_ce_SplSubject;
      76                 : PHPAPI zend_class_entry     *spl_ce_SplObjectStorage;
      77                 : PHPAPI zend_class_entry     *spl_ce_MultipleIterator;
      78                 : 
      79                 : PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
      80                 : 
      81                 : typedef struct _spl_SplObjectStorage { /* {{{ */
      82                 :         zend_object       std;
      83                 :         HashTable         storage;
      84                 :         long              index;
      85                 :         HashPosition      pos;
      86                 :         long              flags;
      87                 :         HashTable        *debug_info;
      88                 : } spl_SplObjectStorage; /* }}} */
      89                 : 
      90                 : /* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */
      91                 : typedef struct _spl_SplObjectStorageElement {
      92                 :         zval* obj;
      93                 :         zval* inf;
      94                 : } spl_SplObjectStorageElement; /* }}} */
      95                 : 
      96                 : void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */
      97              67 : {
      98              67 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage *)object;
      99                 : 
     100              67 :         zend_object_std_dtor(&intern->std TSRMLS_CC);
     101                 :         
     102              67 :         zend_hash_destroy(&intern->storage);
     103                 : 
     104              67 :         if (intern->debug_info != NULL) {
     105              11 :                 zend_hash_destroy(intern->debug_info);
     106              11 :                 efree(intern->debug_info);
     107                 :         
     108                 :         }
     109                 : 
     110                 : 
     111              67 :         efree(object);
     112              67 : } /* }}} */
     113                 : 
     114                 : static void spl_object_storage_dtor(spl_SplObjectStorageElement *element) /* {{{ */
     115              65 : {
     116              65 :         zval_ptr_dtor(&element->obj);
     117              65 :         zval_ptr_dtor(&element->inf);
     118              65 : } /* }}} */
     119                 : 
     120                 : spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
     121              74 : {
     122                 :         spl_SplObjectStorageElement *element;
     123                 :         zend_object_value *pzvalue;     
     124                 : #if HAVE_PACKED_OBJECT_VALUE
     125              74 :         pzvalue = &Z_OBJVAL_P(obj);
     126                 : #else
     127                 :         zend_object_value zvalue;
     128                 :         memset(&zvalue, 0, sizeof(zend_object_value));
     129                 :         zvalue.handle = Z_OBJ_HANDLE_P(obj);
     130                 :         zvalue.handlers = Z_OBJ_HT_P(obj);
     131                 :         pzvalue = &zvalue;
     132                 : #endif
     133              74 :         if (zend_hash_find(&intern->storage, (char*)pzvalue, sizeof(zend_object_value), (void**)&element) == SUCCESS) {
     134               8 :                 return element;
     135                 :         } else {
     136              66 :                 return NULL;
     137                 :         }
     138                 : } /* }}} */
     139                 : 
     140                 : void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *obj, zval *inf TSRMLS_DC) /* {{{ */
     141              72 : {
     142                 :         spl_SplObjectStorageElement *pelement, element;
     143              72 :         pelement = spl_object_storage_get(intern, obj TSRMLS_CC);
     144              72 :         if (inf) {
     145              50 :                 Z_ADDREF_P(inf);
     146                 :         } else {
     147              22 :                 ALLOC_INIT_ZVAL(inf);
     148                 :         }
     149              72 :         if (pelement) {
     150               7 :                 zval_ptr_dtor(&pelement->inf);
     151               7 :                 pelement->inf = inf;
     152               7 :                 return;
     153                 :         }
     154              65 :         Z_ADDREF_P(obj);
     155              65 :         element.obj = obj;
     156              65 :         element.inf = inf;
     157                 : #if HAVE_PACKED_OBJECT_VALUE
     158              65 :         zend_hash_update(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value), &element, sizeof(spl_SplObjectStorageElement), NULL);     
     159                 : #else
     160                 :         {
     161                 :                 zend_object_value zvalue;
     162                 :                 memset(&zvalue, 0, sizeof(zend_object_value));
     163                 :                 zvalue.handle = Z_OBJ_HANDLE_P(obj);
     164                 :                 zvalue.handlers = Z_OBJ_HT_P(obj);
     165                 :                 zend_hash_update(&intern->storage, (char*)&zvalue, sizeof(zend_object_value), &element, sizeof(spl_SplObjectStorageElement), NULL);
     166                 :         }
     167                 : #endif
     168                 : } /* }}} */
     169                 : 
     170                 : void spl_object_storage_detach(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
     171               7 : {
     172                 : #if HAVE_PACKED_OBJECT_VALUE
     173               7 :         zend_hash_del(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
     174                 : #else
     175                 :         {
     176                 :                 zend_object_value zvalue;
     177                 :                 memset(&zvalue, 0, sizeof(zend_object_value));
     178                 :                 zvalue.handle = Z_OBJ_HANDLE_P(obj);
     179                 :                 zvalue.handlers = Z_OBJ_HT_P(obj);
     180                 :                 zend_hash_del(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
     181                 :         }
     182                 : #endif
     183               7 : } /* }}}*/
     184                 : 
     185               2 : void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorage *other TSRMLS_DC) { /* {{{ */
     186                 :         spl_SplObjectStorageElement *element;
     187                 :         HashPosition pos;
     188                 : 
     189               2 :         zend_hash_internal_pointer_reset_ex(&other->storage, &pos);
     190               8 :         while (zend_hash_get_current_data_ex(&other->storage, (void **)&element, &pos) == SUCCESS) {
     191               4 :                 spl_object_storage_attach(intern, element->obj, element->inf TSRMLS_CC);
     192               4 :                 zend_hash_move_forward_ex(&other->storage, &pos);
     193                 :         }
     194                 : 
     195               2 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     196               2 :         intern->index = 0;
     197               2 : } /* }}} */
     198                 : 
     199                 : static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type, spl_SplObjectStorage **obj, zval *orig TSRMLS_DC) /* {{{ */
     200              67 : {
     201                 :         zend_object_value retval;
     202                 :         spl_SplObjectStorage *intern;
     203                 :         zval *tmp;
     204                 : 
     205              67 :         intern = emalloc(sizeof(spl_SplObjectStorage));
     206              67 :         memset(intern, 0, sizeof(spl_SplObjectStorage));
     207              67 :         *obj = intern;
     208                 : 
     209              67 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
     210              67 :         zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
     211                 : 
     212              67 :         zend_hash_init(&intern->storage, 0, NULL, (void (*)(void *))spl_object_storage_dtor, 0);
     213                 : 
     214              67 :         retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_SplOjectStorage_free_storage, NULL TSRMLS_CC);
     215              67 :         retval.handlers = &spl_handler_SplObjectStorage;
     216                 : 
     217              67 :         if (orig) {
     218               1 :                 spl_SplObjectStorage *other = (spl_SplObjectStorage*)zend_object_store_get_object(orig TSRMLS_CC);
     219               1 :                 spl_object_storage_addall(intern, other TSRMLS_CC);
     220                 :         }
     221                 : 
     222              67 :         return retval;
     223                 : }
     224                 : /* }}} */
     225                 : 
     226                 : /* {{{ spl_object_storage_clone */
     227                 : static zend_object_value spl_object_storage_clone(zval *zobject TSRMLS_DC)
     228               1 : {
     229                 :         zend_object_value new_obj_val;
     230                 :         zend_object *old_object;
     231                 :         zend_object *new_object;
     232               1 :         zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
     233                 :         spl_SplObjectStorage *intern;
     234                 : 
     235               1 :         old_object = zend_objects_get_address(zobject TSRMLS_CC);
     236               1 :         new_obj_val = spl_object_storage_new_ex(old_object->ce, &intern, zobject TSRMLS_CC);
     237               1 :         new_object = &intern->std;
     238                 : 
     239               1 :         zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
     240                 : 
     241               1 :         return new_obj_val;
     242                 : }
     243                 : /* }}} */
     244                 : 
     245                 : 
     246                 : static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
     247              13 : {
     248              13 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC);
     249                 :         spl_SplObjectStorageElement *element;
     250                 :         HashTable *props;
     251                 :         HashPosition pos;
     252                 :         zval *tmp, *storage;
     253                 :         char md5str[33];
     254                 :         int name_len;
     255                 :         zstr zname;
     256                 : 
     257              13 :         *is_temp = 0;
     258                 : 
     259              13 :         props = Z_OBJPROP_P(obj);
     260              13 :         if (intern->debug_info == NULL) {
     261              11 :                 ALLOC_HASHTABLE(intern->debug_info);
     262              11 :                 ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(props) + 1, 0);
     263                 :         }
     264                 : 
     265              13 :         if (intern->debug_info->nApplyCount == 0) {
     266              11 :                 zend_hash_copy(intern->debug_info, props, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
     267                 : 
     268              11 :                 MAKE_STD_ZVAL(storage);
     269              11 :                 array_init(storage);
     270                 : 
     271              11 :                 zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
     272              49 :                 while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) {
     273              27 :                                 php_spl_object_hash(element->obj, md5str TSRMLS_CC);
     274              27 :                                 Z_ADDREF_P(element->obj);
     275              27 :                                 Z_ADDREF_P(element->inf);
     276              27 :                                 MAKE_STD_ZVAL(tmp);
     277              27 :                                 array_init(tmp);
     278              27 :                                 add_assoc_zval_ex(tmp, "obj", sizeof("obj"), element->obj);
     279              27 :                                 add_assoc_zval_ex(tmp, "inf", sizeof("inf"), element->inf);
     280              27 :                                 add_assoc_zval_ex(storage, md5str, 33, tmp);
     281              27 :                                 zend_hash_move_forward_ex(&intern->storage, &pos);
     282                 :                 }
     283                 : 
     284              11 :                 zname = spl_gen_private_prop_name(spl_ce_SplObjectStorage, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
     285              11 :                 zend_u_symtable_update(intern->debug_info, IS_UNICODE, zname, name_len+1, &storage, sizeof(zval *), NULL);
     286              11 :                 efree(zname.v);
     287                 :         }
     288                 : 
     289              13 :         return intern->debug_info;
     290                 : }
     291                 : /* }}} */
     292                 : 
     293                 : static int spl_object_storage_compare_info(spl_SplObjectStorageElement *e1, spl_SplObjectStorageElement *e2 TSRMLS_DC) /* {{{ */
     294               2 : {
     295                 :         zval result;
     296                 : 
     297               2 :         if (compare_function(&result, e1->inf, e2->inf TSRMLS_CC) == FAILURE) {
     298               0 :                 return 1;
     299                 :         }
     300                 : 
     301               2 :         return Z_LVAL(result);
     302                 : }
     303                 : /* }}} */
     304                 : 
     305                 : static int spl_object_storage_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
     306               4 : {
     307               4 :         zend_object *zo1 = (zend_object *)zend_object_store_get_object(o1 TSRMLS_CC);
     308               4 :         zend_object *zo2 = (zend_object *)zend_object_store_get_object(o2 TSRMLS_CC);
     309                 : 
     310               4 :         if (zo1->ce != spl_ce_SplObjectStorage || zo2->ce != spl_ce_SplObjectStorage) {
     311               0 :                 return 1;
     312                 :         }
     313                 : 
     314               4 :         return zend_hash_compare(&((spl_SplObjectStorage *)zo1)->storage, &((spl_SplObjectStorage *)zo2)->storage, (compare_func_t) spl_object_storage_compare_info, 0 TSRMLS_CC);
     315                 : }
     316                 : /* }}} */
     317                 : 
     318                 : /* {{{ spl_array_object_new */
     319                 : static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC)
     320              66 : {
     321                 :         spl_SplObjectStorage *tmp;
     322              66 :         return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC);
     323                 : }
     324                 : /* }}} */
     325                 : 
     326                 : int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
     327               4 : {
     328                 : #if HAVE_PACKED_OBJECT_VALUE
     329               4 :         return zend_hash_exists(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
     330                 : #else
     331                 :         {
     332                 :                 zend_object_value zvalue;
     333                 :                 memset(&zvalue, 0, sizeof(zend_object_value));
     334                 :                 zvalue.handle = Z_OBJ_HANDLE_P(obj);
     335                 :                 zvalue.handlers = Z_OBJ_HT_P(obj);
     336                 :                 return zend_hash_exists(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
     337                 :         }
     338                 : #endif
     339                 : } /* }}} */
     340                 : 
     341                 : /* {{{ proto void SplObjectStorage::attach($obj, $inf = NULL) U
     342                 :  Attaches an object to the storage if not yet contained */
     343                 : SPL_METHOD(SplObjectStorage, attach)
     344              39 : {
     345              39 :         zval *obj, *inf = NULL;
     346                 : 
     347              39 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     348                 : 
     349              39 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|z!", &obj, &inf) == FAILURE) {
     350               2 :                 return;
     351                 :         }
     352              37 :         spl_object_storage_attach(intern, obj, inf TSRMLS_CC);
     353                 : } /* }}} */
     354                 : 
     355                 : /* {{{ proto void SplObjectStorage::detach($obj) U
     356                 :  Detaches an object from the storage */
     357                 : SPL_METHOD(SplObjectStorage, detach)
     358              11 : {
     359                 :         zval *obj;
     360              11 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     361                 : 
     362              11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
     363               6 :                 return;
     364                 :         }
     365               5 :         spl_object_storage_detach(intern, obj TSRMLS_CC);
     366                 : 
     367               5 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     368               5 :         intern->index = 0;
     369                 : } /* }}} */
     370                 : 
     371                 : /* {{{ proto mixed SplObjectStorage::offsetGet($object) U
     372                 :  Returns associated information for a stored object */
     373                 : SPL_METHOD(SplObjectStorage, offsetGet)
     374               8 : {
     375                 :         zval *obj;
     376                 :         spl_SplObjectStorageElement *element;
     377               8 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     378                 :         
     379               8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
     380               6 :                 return;
     381                 :         }
     382               2 :         element = spl_object_storage_get(intern, obj TSRMLS_CC);
     383               2 :         if (!element) {
     384               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Object not found");
     385                 :         } else {
     386               1 :                 RETURN_ZVAL(element->inf,1, 0);
     387                 :         }
     388                 : } /* }}} */
     389                 : 
     390                 : /* {{{ proto bool SplObjectStorage::addAll(SplObjectStorage $os)
     391                 :  Add all elements contained in $os */
     392                 : SPL_METHOD(SplObjectStorage, addAll)
     393               7 : {
     394                 :         zval *obj;
     395               7 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
     396                 :         spl_SplObjectStorage *other;
     397                 : 
     398               7 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
     399               6 :                 return;
     400                 :         }
     401                 : 
     402               1 :         other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
     403                 : 
     404               1 :         spl_object_storage_addall(intern, other TSRMLS_CC);
     405                 : 
     406               1 :         RETURN_LONG(zend_hash_num_elements(&intern->storage));
     407                 : } /* }}} */
     408                 : 
     409                 : /* {{{ proto bool SplObjectStorage::removeAll(SplObjectStorage $os)
     410                 :  Remove all elements contained in $os */
     411                 : SPL_METHOD(SplObjectStorage, removeAll)
     412               7 : {
     413                 :         zval *obj;
     414               7 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
     415                 :         spl_SplObjectStorage *other;
     416                 :         spl_SplObjectStorageElement *element;
     417                 :         HashPosition pos;
     418                 : 
     419               7 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
     420               6 :                 return;
     421                 :         }
     422                 : 
     423               1 :         other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
     424                 : 
     425               1 :         zend_hash_internal_pointer_reset_ex(&other->storage, &pos);
     426               4 :         while (zend_hash_get_current_data_ex(&other->storage, (void **)&element, &pos) == SUCCESS) {
     427               2 :                 spl_object_storage_detach(intern, element->obj TSRMLS_CC);
     428               2 :                 zend_hash_move_forward_ex(&other->storage, &pos);
     429                 :         }
     430                 : 
     431               1 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     432               1 :         intern->index = 0;
     433                 : 
     434               1 :         RETURN_LONG(zend_hash_num_elements(&intern->storage));
     435                 : } /* }}} */
     436                 : 
     437                 : /* {{{ proto bool SplObjectStorage::contains($obj) U
     438                 :  Determine whethe an object is contained in the storage */
     439                 : SPL_METHOD(SplObjectStorage, contains)
     440              10 : {
     441                 :         zval *obj;
     442              10 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     443                 : 
     444              10 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
     445               6 :                 return;
     446                 :         }
     447               4 :         RETURN_BOOL(spl_object_storage_contains(intern, obj TSRMLS_CC));
     448                 : } /* }}} */
     449                 : 
     450                 : /* {{{ proto int SplObjectStorage::count() U
     451                 :  Determine number of objects in storage */
     452                 : SPL_METHOD(SplObjectStorage, count)
     453              19 : {
     454              19 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     455                 :         
     456              19 :         RETURN_LONG(zend_hash_num_elements(&intern->storage));
     457                 : } /* }}} */
     458                 : 
     459                 : /* {{{ proto void SplObjectStorage::rewind() U
     460                 :  Rewind to first position */
     461                 : SPL_METHOD(SplObjectStorage, rewind)
     462              16 : {
     463              16 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     464                 :         
     465              16 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     466              16 :         intern->index = 0;
     467              16 : } /* }}} */
     468                 : 
     469                 : /* {{{ proto bool SplObjectStorage::valid() U
     470                 :  Returns whether current position is valid */
     471                 : SPL_METHOD(SplObjectStorage, valid)
     472              54 : {
     473              54 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     474                 :         
     475              54 :         RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS);
     476                 : } /* }}} */
     477                 : 
     478                 : /* {{{ proto mixed SplObjectStorage::key() U
     479                 :  Returns current key */
     480                 : SPL_METHOD(SplObjectStorage, key)
     481              14 : {
     482              14 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     483                 :         
     484              14 :         RETURN_LONG(intern->index);
     485                 : } /* }}} */
     486                 : 
     487                 : /* {{{ proto mixed SplObjectStorage::current() U
     488                 :  Returns current element */
     489                 : SPL_METHOD(SplObjectStorage, current)
     490              40 : {
     491                 :         spl_SplObjectStorageElement *element;
     492              40 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     493                 :         
     494              40 :         if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
     495               1 :                 return;
     496                 :         }
     497              39 :         RETVAL_ZVAL(element->obj, 1, 0);
     498                 : } /* }}} */
     499                 : 
     500                 : /* {{{ proto mixed SplObjectStorage::getInfo() U
     501                 :  Returns associated information to current element */
     502                 : SPL_METHOD(SplObjectStorage, getInfo)
     503               3 : {
     504                 :         spl_SplObjectStorageElement *element;
     505               3 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     506                 :         
     507               3 :         if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
     508               1 :                 return;
     509                 :         }
     510               2 :         RETVAL_ZVAL(element->inf, 1, 0);
     511                 : } /* }}} */
     512                 : 
     513                 : /* {{{ proto mixed SplObjectStorage::setInfo(mixed $inf) U
     514                 :  Sets associated information of current element to $inf */
     515                 : SPL_METHOD(SplObjectStorage, setInfo)
     516               3 : {
     517                 :         spl_SplObjectStorageElement *element;
     518               3 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     519                 :         zval *inf;
     520                 :         
     521               3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &inf) == FAILURE) {
     522               1 :                 return;
     523                 :         }
     524                 : 
     525               2 :         if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
     526               1 :                 return;
     527                 :         }
     528               1 :         zval_ptr_dtor(&element->inf);
     529               1 :         element->inf = inf;
     530               1 :         Z_ADDREF_P(inf);
     531                 : } /* }}} */
     532                 : 
     533                 : /* {{{ proto void SplObjectStorage::next() U
     534                 :  Moves position forward */
     535                 : SPL_METHOD(SplObjectStorage, next)
     536              33 : {
     537              33 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     538                 :         
     539              33 :         zend_hash_move_forward_ex(&intern->storage, &intern->pos);
     540              33 :         intern->index++;
     541              33 : } /* }}} */
     542                 : 
     543                 : /* {{{ proto string SplObjectStorage::serialize() U
     544                 :  Serializes storage */
     545                 : SPL_METHOD(SplObjectStorage, serialize)
     546              12 : {
     547              12 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     548                 : 
     549                 :         spl_SplObjectStorageElement *element;
     550                 :         zval members, *pmembers;
     551                 :         HashPosition      pos;
     552                 :         php_serialize_data_t var_hash;
     553              12 :         smart_str buf = {0};
     554                 : 
     555              12 :         PHP_VAR_SERIALIZE_INIT(var_hash);
     556                 : 
     557                 :         /* storage */
     558              12 :         smart_str_appendl(&buf, "x:i:", 4);
     559              12 :         smart_str_append_long(&buf, zend_hash_num_elements(&intern->storage));
     560              12 :         smart_str_appendc(&buf, ';');
     561                 : 
     562              12 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
     563                 : 
     564              58 :         while(zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) {
     565              34 :                 if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &pos) == FAILURE) {
     566               0 :                         smart_str_free(&buf);
     567               0 :                         PHP_VAR_SERIALIZE_DESTROY(var_hash);
     568               0 :                         RETURN_NULL();
     569                 :                 }
     570              34 :                 php_var_serialize(&buf, &element->obj, &var_hash TSRMLS_CC);
     571              34 :                 smart_str_appendc(&buf, ',');
     572              34 :                 php_var_serialize(&buf, &element->inf, &var_hash TSRMLS_CC);
     573              34 :                 smart_str_appendc(&buf, ';');
     574              34 :                 zend_hash_move_forward_ex(&intern->storage, &pos);
     575                 :         }
     576                 : 
     577                 :         /* members */
     578              12 :         smart_str_appendl(&buf, "m:", 2);
     579              12 :         INIT_PZVAL(&members);
     580              12 :         Z_ARRVAL(members) = intern->std.properties;
     581              12 :         Z_TYPE(members) = IS_ARRAY;
     582              12 :         pmembers = &members;
     583              12 :         php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
     584                 : 
     585                 :         /* done */
     586              12 :         PHP_VAR_SERIALIZE_DESTROY(var_hash);
     587                 : 
     588              12 :         if (buf.c) {
     589              12 :                 RETURN_STRINGL(buf.c, buf.len, 0);
     590                 :         } else {
     591               0 :                 RETURN_NULL();
     592                 :         }
     593                 :         
     594                 : } /* }}} */
     595                 : 
     596                 : /* {{{ proto void SplObjectStorage::unserialize(string serialized) U
     597                 :  Unserializes storage */
     598                 : SPL_METHOD(SplObjectStorage, unserialize)
     599              16 : {
     600              16 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     601                 : 
     602                 :         char *buf;
     603                 :         int buf_len;
     604                 :         const unsigned char *p, *s;
     605                 :         php_unserialize_data_t var_hash;
     606              16 :         zval *pentry, *pmembers, *pcount = NULL, *pinf;
     607                 :         long count;
     608                 :         
     609              16 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
     610               2 :                 return;
     611                 :         }
     612                 : 
     613              14 :         if (buf_len == 0) {
     614               1 :                 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Serialized string cannot be empty");
     615               1 :                 return;
     616                 :         }
     617                 : 
     618                 :         /* storage */
     619              13 :         s = p = (const unsigned char*)buf;
     620              13 :         PHP_VAR_UNSERIALIZE_INIT(var_hash);
     621                 : 
     622              13 :         if (*p!= 'x' || *++p != ':') {
     623                 :                 goto outexcept;
     624                 :         }
     625              10 :         ++p;
     626                 : 
     627              10 :         ALLOC_INIT_ZVAL(pcount);
     628              10 :         if (!php_var_unserialize(&pcount, &p, s + buf_len, NULL TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
     629               1 :                 zval_ptr_dtor(&pcount);
     630               1 :                 goto outexcept;
     631                 :         }
     632                 : 
     633               9 :         --p; /* for ';' */
     634               9 :         count = Z_LVAL_P(pcount);
     635               9 :         zval_ptr_dtor(&pcount);
     636                 :                 
     637              43 :         while(count-- > 0) {
     638              26 :                 if (*p != ';') {
     639               0 :                         goto outexcept;
     640                 :                 }
     641              26 :                 ++p;
     642              26 :                 ALLOC_INIT_ZVAL(pentry);
     643              26 :                 if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) {
     644               1 :                         zval_ptr_dtor(&pentry);
     645               1 :                         goto outexcept;
     646                 :                 }
     647              25 :                 ALLOC_INIT_ZVAL(pinf);
     648              25 :                 if (*p == ',') { /* new version has inf */
     649              25 :                         ++p;
     650              25 :                         if (!php_var_unserialize(&pinf, &p, s + buf_len, &var_hash TSRMLS_CC)) {
     651               0 :                                 zval_ptr_dtor(&pinf);
     652               0 :                                 goto outexcept;
     653                 :                         }
     654                 :                 }
     655              25 :                 spl_object_storage_attach(intern, pentry, pinf TSRMLS_CC);
     656              25 :                 zval_ptr_dtor(&pentry);
     657              25 :                 zval_ptr_dtor(&pinf);
     658                 :         }
     659                 : 
     660               8 :         if (*p != ';') {
     661               0 :                 goto outexcept;
     662                 :         }
     663               8 :         ++p;
     664                 : 
     665                 :         /* members */
     666               8 :         if (*p!= 'm' || *++p != ':') {
     667                 :                 goto outexcept;
     668                 :         }
     669               8 :         ++p;
     670                 : 
     671               8 :         ALLOC_INIT_ZVAL(pmembers);
     672               8 :         if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
     673               0 :                 zval_ptr_dtor(&pmembers);
     674               0 :                 goto outexcept;
     675                 :         }
     676                 : 
     677                 :         /* copy members */
     678               8 :         zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
     679               8 :         zval_ptr_dtor(&pmembers);
     680                 : 
     681                 :         /* done reading $serialized */
     682                 : 
     683               8 :         PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
     684               8 :         return;
     685                 : 
     686               5 : outexcept:
     687               5 :         PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
     688               5 :         zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
     689               5 :         return;
     690                 : 
     691                 : } /* }}} */
     692                 : 
     693                 : ZEND_BEGIN_ARG_INFO(arginfo_Object, 0)
     694                 :         ZEND_ARG_INFO(0, object)
     695                 : ZEND_END_ARG_INFO();
     696                 : 
     697                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_attach, 0, 0, 1)
     698                 :         ZEND_ARG_INFO(0, object)
     699                 :         ZEND_ARG_INFO(0, inf)
     700                 : ZEND_END_ARG_INFO();
     701                 : 
     702                 : ZEND_BEGIN_ARG_INFO(arginfo_Serialized, 0)
     703                 :         ZEND_ARG_INFO(0, serialized)
     704                 : ZEND_END_ARG_INFO();
     705                 : 
     706                 : ZEND_BEGIN_ARG_INFO(arginfo_setInfo, 0)
     707                 :         ZEND_ARG_INFO(0, info)
     708                 : ZEND_END_ARG_INFO();
     709                 : 
     710                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
     711                 :         ZEND_ARG_INFO(0, object)
     712                 : ZEND_END_ARG_INFO()
     713                 : 
     714                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
     715                 :         ZEND_ARG_INFO(0, object)
     716                 :         ZEND_ARG_INFO(0, info)
     717                 : ZEND_END_ARG_INFO()
     718                 : 
     719                 : typedef enum {
     720                 :         MIT_NEED_ANY     = 0,
     721                 :         MIT_NEED_ALL     = 1,
     722                 :         MIT_KEYS_NUMERIC = 0,
     723                 :         MIT_KEYS_ASSOC   = 2
     724                 : } MultipleIteratorFlags;
     725                 : 
     726                 : #define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT   1
     727                 : #define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY       2
     728                 : 
     729                 : /* {{{ proto void MultipleIterator::__construct([int flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC]) U
     730                 :    Iterator that iterates over several iterators one after the other */
     731                 : SPL_METHOD(MultipleIterator, __construct)
     732               1 : {
     733                 :         spl_SplObjectStorage   *intern;
     734               1 :         long                    flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC;
     735                 :         zend_error_handling error_handling;
     736                 : 
     737               1 :         zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
     738                 : 
     739               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
     740               0 :                 zend_restore_error_handling(&error_handling TSRMLS_CC);
     741               0 :                 return;
     742                 :         }
     743                 : 
     744               1 :         intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     745               1 :         intern->flags = flags;
     746               1 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
     747                 : }
     748                 : /* }}} */
     749                 : 
     750                 : /* {{{ proto int MultipleIterator::getFlags() U
     751                 :    Return current flags */
     752                 : SPL_METHOD(MultipleIterator, getFlags)
     753               2 : {
     754               2 :         spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     755               2 :         RETURN_LONG(intern->flags);
     756                 : }
     757                 : /* }}} */
     758                 : 
     759                 : /* {{{ proto int MultipleIterator::setFlags(int flags) U
     760                 :    Set flags */
     761                 : SPL_METHOD(MultipleIterator, setFlags)
     762               3 : {
     763                 :         spl_SplObjectStorage *intern;
     764               3 :         intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     765                 : 
     766               3 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) {
     767                 :                 return;
     768                 :         }
     769                 : }
     770                 : /* }}} */
     771                 : 
     772                 : /* {{{ proto void attachIterator(Iterator iterator[, mixed info]) throws InvalidArgumentException U
     773                 :    Attach a new iterator */
     774                 : SPL_METHOD(MultipleIterator, attachIterator)
     775               8 : {
     776                 :         spl_SplObjectStorage        *intern;
     777               8 :         zval                        *iterator = NULL, *info = NULL;
     778                 : 
     779               8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|z!", &iterator, zend_ce_iterator, &info) == FAILURE) {
     780               0 :                 return;
     781                 :         }
     782                 : 
     783               8 :         intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     784                 : 
     785               8 :         if (info != NULL) {
     786                 :                 spl_SplObjectStorageElement *element;
     787                 :                 zval                         compare_result;
     788                 : 
     789               5 :                 if (Z_TYPE_P(info) != IS_LONG && Z_TYPE_P(info) != IS_STRING && Z_TYPE_P(info) != IS_UNICODE) {
     790               1 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "Info must be NULL, integer or string", 0 TSRMLS_CC);
     791               1 :                         return;
     792                 :                 }
     793                 : 
     794               4 :                 zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     795              17 :                 while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS) {
     796              10 :                         is_identical_function(&compare_result, info, element->inf TSRMLS_CC);
     797              10 :                         if (Z_LVAL(compare_result)) {
     798               1 :                                 zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0 TSRMLS_CC);
     799               1 :                                 return;
     800                 :                         }
     801               9 :                         zend_hash_move_forward_ex(&intern->storage, &intern->pos);
     802                 :                 }
     803                 :         }
     804                 : 
     805               6 :         spl_object_storage_attach(intern, iterator, info TSRMLS_CC);
     806                 : }
     807                 : /* }}} */
     808                 : 
     809                 : /* {{{ proto void MultipleIterator::rewind() U
     810                 :    Rewind all attached iterator instances */
     811                 : SPL_METHOD(MultipleIterator, rewind)
     812               7 : {
     813                 :         spl_SplObjectStorage        *intern;
     814                 :         spl_SplObjectStorageElement *element;
     815                 :         zval                        *it;
     816                 : 
     817               7 :         intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     818                 : 
     819               7 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     820              31 :         while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
     821              17 :                 it = element->obj;
     822              17 :                 zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL);
     823              17 :                 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
     824                 :         }
     825               7 : }
     826                 : /* }}} */
     827                 : 
     828                 : /* {{{ proto void MultipleIterator::next() U
     829                 :    Move all attached iterator instances forward */
     830                 : SPL_METHOD(MultipleIterator, next)
     831              14 : {
     832                 :         spl_SplObjectStorage        *intern;
     833                 :         spl_SplObjectStorageElement *element;
     834                 :         zval                        *it;
     835                 : 
     836              14 :         intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     837                 : 
     838              14 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     839              67 :         while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
     840              39 :                 it = element->obj;
     841              39 :                 zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL);
     842              39 :                 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
     843                 :         }
     844              14 : }
     845                 : /* }}} */
     846                 : 
     847                 : /* {{{ proto bool MultipleIterator::valid() U
     848                 :    Return whether all or one sub iterator is valid depending on flags */
     849                 : SPL_METHOD(MultipleIterator, valid)
     850              20 : {
     851                 :         spl_SplObjectStorage        *intern;
     852                 :         spl_SplObjectStorageElement *element;
     853              20 :         zval                        *it, *retval = NULL;
     854                 :         long                         expect, valid;
     855                 : 
     856              20 :         intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     857                 : 
     858              20 :         if (!zend_hash_num_elements(&intern->storage)) {
     859               1 :                 RETURN_FALSE;
     860                 :         }
     861                 : 
     862              19 :         expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0;
     863                 : 
     864              19 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     865              72 :         while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
     866              41 :                 it = element->obj;
     867              41 :                 zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
     868                 : 
     869              41 :                 if (retval) {
     870              41 :                         valid = Z_LVAL_P(retval);
     871              41 :                         zval_ptr_dtor(&retval);
     872                 :                 } else {
     873               0 :                         valid = 0;
     874                 :                 }
     875                 : 
     876              41 :                 if (expect != valid) {
     877               7 :                         RETURN_BOOL(!expect);
     878                 :                 }
     879                 : 
     880              34 :                 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
     881                 :         }
     882                 : 
     883              12 :         RETURN_BOOL(expect);
     884                 : }
     885                 : /* }}} */
     886                 : 
     887                 : static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value TSRMLS_DC) /* {{{ */
     888              32 : {
     889                 :         spl_SplObjectStorageElement *element;
     890              32 :         zval                        *it, *retval = NULL;
     891              32 :         int                          valid = 1, num_elements;
     892                 : 
     893              32 :         num_elements = zend_hash_num_elements(&intern->storage);
     894              32 :         if (num_elements < 1) {
     895               1 :                 RETURN_FALSE;
     896                 :         }
     897                 : 
     898              31 :         array_init_size(return_value, num_elements);
     899                 :         
     900              31 :         zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
     901             142 :         while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
     902              83 :                 it = element->obj;
     903              83 :                 zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
     904                 : 
     905              83 :                 if (retval) {
     906              83 :                         valid = Z_LVAL_P(retval);
     907              83 :                         zval_ptr_dtor(&retval);
     908                 :                 } else {
     909               0 :                         valid = 0;
     910                 :                 }
     911                 : 
     912              83 :                 if (valid) {
     913              79 :                         if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
     914              40 :                                 zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval);
     915                 :                         } else {
     916              39 :                                 zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key,     "key",     &retval);
     917                 :                         }
     918              79 :                         if (!retval) {
     919               0 :                                 zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0 TSRMLS_CC);
     920               0 :                                 return;
     921                 :                         }
     922               4 :                 } else if (intern->flags & MIT_NEED_ALL) {
     923               2 :                         if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
     924               1 :                                 zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0 TSRMLS_CC);
     925                 :                         } else {
     926               1 :                                 zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0 TSRMLS_CC);
     927                 :                         }
     928               2 :                         return;
     929                 :                 } else {
     930               2 :                         ALLOC_INIT_ZVAL(retval);
     931                 :                 }
     932                 : 
     933              81 :                 if (intern->flags & MIT_KEYS_ASSOC) {
     934              31 :                         switch (Z_TYPE_P(element->inf)) {
     935                 :                                 case IS_LONG:
     936              12 :                                         add_index_zval(return_value, Z_LVAL_P(element->inf), retval);
     937              12 :                                         break;
     938                 :                                 case IS_STRING:
     939                 :                                 case IS_UNICODE:
     940              18 :                                         add_u_assoc_zval_ex(return_value, Z_TYPE_P(element->inf), Z_UNIVAL_P(element->inf), Z_UNILEN_P(element->inf)+1U, retval);
     941              18 :                                         break;
     942                 :                                 default:
     943               1 :                                         zval_ptr_dtor(&retval);
     944               1 :                                         zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0 TSRMLS_CC);
     945               1 :                                         return;
     946                 :                         }
     947                 :                 } else {
     948              50 :                         add_next_index_zval(return_value, retval);
     949                 :                 }
     950                 : 
     951              80 :                 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
     952                 :         }
     953                 : }
     954                 : /* }}} */
     955                 : 
     956                 : /* {{{ proto array current() throws RuntimeException throws InvalidArgumentException U
     957                 :    Return an array of all registered Iterator instances current() result */
     958                 : SPL_METHOD(MultipleIterator, current)
     959              17 : {
     960                 :         spl_SplObjectStorage        *intern;
     961              17 :         intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     962                 : 
     963              17 :         spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value TSRMLS_CC);
     964              17 : }
     965                 : /* }}} */
     966                 : 
     967                 : /* {{{ proto array MultipleIterator::key() U
     968                 :    Return an array of all registered Iterator instances key() result */
     969                 : SPL_METHOD(MultipleIterator, key)
     970              15 : {
     971                 :         spl_SplObjectStorage        *intern;
     972              15 :         intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
     973                 : 
     974              15 :         spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value TSRMLS_CC);
     975              15 : }
     976                 : /* }}} */
     977                 : 
     978                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1)
     979                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
     980                 :         ZEND_ARG_INFO(0, infos)
     981                 : ZEND_END_ARG_INFO();
     982                 : 
     983                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_detachIterator, 0, 0, 1)
     984                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
     985                 : ZEND_END_ARG_INFO();
     986                 : 
     987                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_containsIterator, 0, 0, 1)
     988                 :         ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
     989                 : ZEND_END_ARG_INFO();
     990                 : 
     991                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_setflags, 0, 0, 1)
     992                 :         ZEND_ARG_INFO(0, flags)
     993                 : ZEND_END_ARG_INFO();
     994                 : 
     995                 : ZEND_BEGIN_ARG_INFO(arginfo_splobject_void, 0)
     996                 : ZEND_END_ARG_INFO();
     997                 : 
     998                 : static const zend_function_entry spl_funcs_MultipleIterator[] = {
     999                 :         SPL_ME(MultipleIterator,  __construct,            arginfo_MultipleIterator_setflags,          0)
    1000                 :         SPL_ME(MultipleIterator,  getFlags,               arginfo_splobject_void,                     0)
    1001                 :         SPL_ME(MultipleIterator,  setFlags,               arginfo_MultipleIterator_setflags,          0)
    1002                 :         SPL_ME(MultipleIterator,  attachIterator,         arginfo_MultipleIterator_attachIterator,    0)
    1003                 :         SPL_MA(MultipleIterator,  detachIterator,         SplObjectStorage, detach,   arginfo_MultipleIterator_detachIterator,   0)
    1004                 :         SPL_MA(MultipleIterator,  containsIterator,       SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0)
    1005                 :         SPL_MA(MultipleIterator,  countIterators,         SplObjectStorage, count,    arginfo_splobject_void,                    0)
    1006                 :         /* Iterator */
    1007                 :         SPL_ME(MultipleIterator,  rewind,                 arginfo_splobject_void,                     0)
    1008                 :         SPL_ME(MultipleIterator,  valid,                  arginfo_splobject_void,                     0)
    1009                 :         SPL_ME(MultipleIterator,  key,                    arginfo_splobject_void,                     0)
    1010                 :         SPL_ME(MultipleIterator,  current,                arginfo_splobject_void,                     0)
    1011                 :         SPL_ME(MultipleIterator,  next,                   arginfo_splobject_void,                     0)
    1012                 :         {NULL, NULL, NULL}
    1013                 : };
    1014                 : 
    1015                 : static const zend_function_entry spl_funcs_SplObjectStorage[] = {
    1016                 :         SPL_ME(SplObjectStorage,  attach,      arginfo_attach,        0)
    1017                 :         SPL_ME(SplObjectStorage,  detach,      arginfo_Object,        0)
    1018                 :         SPL_ME(SplObjectStorage,  contains,    arginfo_Object,        0)
    1019                 :         SPL_ME(SplObjectStorage,  addAll,      arginfo_Object,        0)
    1020                 :         SPL_ME(SplObjectStorage,  removeAll,   arginfo_Object,        0)
    1021                 :         SPL_ME(SplObjectStorage,  getInfo,     arginfo_splobject_void,0)
    1022                 :         SPL_ME(SplObjectStorage,  setInfo,     arginfo_setInfo,       0)
    1023                 :         /* Countable */
    1024                 :         SPL_ME(SplObjectStorage,  count,       arginfo_splobject_void,0)
    1025                 :         /* Iterator */
    1026                 :         SPL_ME(SplObjectStorage,  rewind,      arginfo_splobject_void,0)
    1027                 :         SPL_ME(SplObjectStorage,  valid,       arginfo_splobject_void,0)
    1028                 :         SPL_ME(SplObjectStorage,  key,         arginfo_splobject_void,0)
    1029                 :         SPL_ME(SplObjectStorage,  current,     arginfo_splobject_void,0)
    1030                 :         SPL_ME(SplObjectStorage,  next,        arginfo_splobject_void,0)
    1031                 :         /* Serializable */
    1032                 :         SPL_ME(SplObjectStorage,  unserialize, arginfo_Serialized,    0)
    1033                 :         SPL_ME(SplObjectStorage,  serialize,   arginfo_splobject_void,0)
    1034                 :         /* ArrayAccess */
    1035                 :         SPL_MA(SplObjectStorage, offsetExists, SplObjectStorage, contains, arginfo_offsetGet, 0)
    1036                 :         SPL_MA(SplObjectStorage, offsetSet,    SplObjectStorage, attach,   arginfo_offsetSet, 0)
    1037                 :         SPL_MA(SplObjectStorage, offsetUnset,  SplObjectStorage, detach,   arginfo_offsetGet, 0)
    1038                 :         SPL_ME(SplObjectStorage, offsetGet,    arginfo_offsetGet,     0)
    1039                 :         {NULL, NULL, NULL}
    1040                 : };
    1041                 : 
    1042                 : /* {{{ PHP_MINIT_FUNCTION(spl_observer) */
    1043                 : PHP_MINIT_FUNCTION(spl_observer)
    1044           17007 : {
    1045           17007 :         REGISTER_SPL_INTERFACE(SplObserver);
    1046           17007 :         REGISTER_SPL_INTERFACE(SplSubject);
    1047                 : 
    1048           17007 :         REGISTER_SPL_STD_CLASS_EX(SplObjectStorage, spl_SplObjectStorage_new, spl_funcs_SplObjectStorage);
    1049           17007 :         memcpy(&spl_handler_SplObjectStorage, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    1050                 : 
    1051           17007 :         spl_handler_SplObjectStorage.get_debug_info  = spl_object_storage_debug_info;
    1052           17007 :         spl_handler_SplObjectStorage.compare_objects = spl_object_storage_compare_objects;
    1053           17007 :         spl_handler_SplObjectStorage.clone_obj       = spl_object_storage_clone;
    1054                 : 
    1055           17007 :         REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable);
    1056           17007 :         REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator);
    1057           17007 :         REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
    1058           17007 :         REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess);
    1059                 : 
    1060           17007 :         REGISTER_SPL_STD_CLASS_EX(MultipleIterator, spl_SplObjectStorage_new, spl_funcs_MultipleIterator);
    1061           17007 :         REGISTER_SPL_ITERATOR(MultipleIterator);
    1062                 : 
    1063           17007 :         REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ANY",     MIT_NEED_ANY);
    1064           17007 :         REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ALL",     MIT_NEED_ALL);
    1065           17007 :         REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_NUMERIC", MIT_KEYS_NUMERIC);
    1066           17007 :         REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_ASSOC",   MIT_KEYS_ASSOC);
    1067                 : 
    1068           17007 :         return SUCCESS;
    1069                 : }
    1070                 : /* }}} */
    1071                 : 
    1072                 : /*
    1073                 :  * Local variables:
    1074                 :  * tab-width: 4
    1075                 :  * c-basic-offset: 4
    1076                 :  * End:
    1077                 :  * vim600: fdm=marker
    1078                 :  * vim: noet sw=4 ts=4
    1079                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:39 +0000 (36 hours ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.