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-21 Instrumented lines: 398
Code covered: 95.2 % Executed lines: 379
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:09 +0000 (3 days ago)

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