SPL_ADD_CLASS(AppendIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(ArrayIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(ArrayObject, z_list, sub, allow, ce_flags); \
- SPL_ADD_CLASS(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \
- SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \
- SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \
- SPL_ADD_CLASS(SplHeap, z_list, sub, allow, ce_flags); \
- SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \
- SPL_ADD_CLASS(SplMaxHeap, z_list, sub, allow, ce_flags); \
- SPL_ADD_CLASS(SplPriorityQueue, z_list, sub, allow, ce_flags); \
- SPL_ADD_CLASS(SplFixedArray, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(LengthException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(LogicException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(MultipleIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(NoRewindIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(OuterIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(OutOfBoundsException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RecursiveIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RecursiveIteratorIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RecursiveRegexIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveTreeIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RegexIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RuntimeException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SeekableIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SimpleXMLIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplFileInfo, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplFileObject, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplFixedArray, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplHeap, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplMaxHeap, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplObjectStorage, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplObserver, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplPriorityQueue, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplSubject, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SplTempFileObject, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \
PHPAPI zend_class_entry *spl_ce_SplObserver;
PHPAPI zend_class_entry *spl_ce_SplSubject;
PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
+PHPAPI zend_class_entry *spl_ce_MultipleIterator;
+
PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
typedef struct _spl_SplObjectStorage { /* {{{ */
HashTable storage;
long index;
HashPosition pos;
+ long flags;
} spl_SplObjectStorage; /* }}} */
/* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */
ZEND_ARG_INFO(0, info)
ZEND_END_ARG_INFO()
+typedef enum {
+ MIT_NEED_ANY = 0,
+ MIT_NEED_ALL = 1,
+ MIT_KEYS_NUMERIC = 0,
+ MIT_KEYS_ASSOC = 2
+} MultipleIteratorFlags;
+
+#define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT 1
+#define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY 2
+
+/* {{{ proto void MultipleIterator::__construct([int flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC]) U
+ Iterator that iterates over several iterators one after the other */
+SPL_METHOD(MultipleIterator, __construct)
+{
+ spl_SplObjectStorage *intern;
+ long flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC;
+
+ php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
+ php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+ return;
+ }
+
+ php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ intern->flags = flags;
+}
+/* }}} */
+
+/* {{{ proto int MultipleIterator::getFlags() U
+ Return current flags */
+SPL_METHOD(MultipleIterator, getFlags)
+{
+ spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ RETURN_LONG(intern->flags);
+}
+/* }}} */
+
+/* {{{ proto int MultipleIterator::setFlags(int flags) U
+ Set flags */
+SPL_METHOD(MultipleIterator, setFlags)
+{
+ spl_SplObjectStorage *intern;
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) {
+ return;
+ }
+}
+/* }}} */
+
+/* {{{ proto void attachIterator(Iterator iterator[, mixed info]) throws InvalidArgumentException U
+ Attach a new iterator */
+SPL_METHOD(MultipleIterator, attachIterator)
+{
+ spl_SplObjectStorage *intern;
+ zval *iterator = NULL, *info = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|z!", &iterator, zend_ce_iterator, &info) == FAILURE) {
+ return;
+ }
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (info != NULL) {
+ spl_SplObjectStorageElement *element;
+ zval compare_result;
+
+ if (Z_TYPE_P(info) != IS_LONG && Z_TYPE_P(info) != IS_STRING && Z_TYPE_P(info) != IS_UNICODE) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Info must be NULL, integer or string", 0 TSRMLS_CC);
+ return;
+ }
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS) {
+ is_identical_function(&compare_result, info, element->inf TSRMLS_CC);
+ if (Z_LVAL(compare_result)) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0 TSRMLS_CC);
+ return;
+ }
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+ }
+
+ spl_object_storage_attach(intern, iterator, info TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void MultipleIterator::rewind() U
+ Rewind all attached iterator instances */
+SPL_METHOD(MultipleIterator, rewind)
+{
+ spl_SplObjectStorage *intern;
+ spl_SplObjectStorageElement *element;
+ zval *it;
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
+ it = element->obj;
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL);
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+}
+/* }}} */
+
+/* {{{ proto void MultipleIterator::next() U
+ Move all attached iterator instances forward */
+SPL_METHOD(MultipleIterator, next)
+{
+ spl_SplObjectStorage *intern;
+ spl_SplObjectStorageElement *element;
+ zval *it;
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
+ it = element->obj;
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL);
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool MultipleIterator::valid() U
+ Return whether all or one sub iterator is valid depending on flags */
+SPL_METHOD(MultipleIterator, valid)
+{
+ spl_SplObjectStorage *intern;
+ spl_SplObjectStorageElement *element;
+ zval *it, *retval = NULL;
+ long expect, valid;
+
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!zend_hash_num_elements(&intern->storage)) {
+ RETURN_FALSE;
+ }
+
+ expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0;
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
+ it = element->obj;
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
+
+ if (retval) {
+ valid = Z_LVAL_P(retval);
+ zval_ptr_dtor(&retval);
+ } else {
+ valid = 0;
+ }
+
+ if (expect != valid) {
+ RETURN_BOOL(!expect);
+ }
+
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+
+ RETURN_BOOL(expect);
+}
+/* }}} */
+
+static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ spl_SplObjectStorageElement *element;
+ zval *it, *retval = NULL;
+ int valid = 1, num_elements;
+
+ num_elements = zend_hash_num_elements(&intern->storage);
+ if (num_elements < 1) {
+ RETURN_FALSE;
+ }
+
+ array_init_size(return_value, num_elements);
+
+ zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
+ while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
+ it = element->obj;
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
+
+ if (retval) {
+ valid = Z_LVAL_P(retval);
+ zval_ptr_dtor(&retval);
+ } else {
+ valid = 0;
+ }
+
+ if (valid) {
+ if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval);
+ } else {
+ zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key, "key", &retval);
+ }
+ if (!retval) {
+ zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0 TSRMLS_CC);
+ return;
+ }
+ } else if (intern->flags & MIT_NEED_ALL) {
+ if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
+ zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0 TSRMLS_CC);
+ } else {
+ zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0 TSRMLS_CC);
+ }
+ return;
+ } else {
+ ALLOC_INIT_ZVAL(retval);
+ }
+
+ if (intern->flags & MIT_KEYS_ASSOC) {
+ switch (Z_TYPE_P(element->inf)) {
+ case IS_LONG:
+ add_index_zval(return_value, Z_LVAL_P(element->inf), retval);
+ break;
+ case IS_STRING:
+ case IS_UNICODE:
+ add_u_assoc_zval_ex(return_value, Z_TYPE_P(element->inf), Z_UNIVAL_P(element->inf), Z_UNILEN_P(element->inf)+1U, retval);
+ break;
+ default:
+ zval_ptr_dtor(&retval);
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0 TSRMLS_CC);
+ return;
+ }
+ } else {
+ add_next_index_zval(return_value, retval);
+ }
+
+ zend_hash_move_forward_ex(&intern->storage, &intern->pos);
+ }
+}
+/* }}} */
+
+/* {{{ proto array current() throws RuntimeException throws InvalidArgumentException U
+ Return an array of all registered Iterator instances current() result */
+SPL_METHOD(MultipleIterator, current)
+{
+ spl_SplObjectStorage *intern;
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto array MultipleIterator::key() U
+ Return an array of all registered Iterator instances key() result */
+SPL_METHOD(MultipleIterator, key)
+{
+ spl_SplObjectStorage *intern;
+ intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value TSRMLS_CC);
+}
+/* }}} */
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ ZEND_ARG_INFO(0, infos)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_detachIterator, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_containsIterator, 0, 0, 1)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_MultipleIterator[] = {
+ SPL_ME(MultipleIterator, __construct, NULL, 0)
+ SPL_ME(MultipleIterator, getFlags, NULL, 0)
+ SPL_ME(MultipleIterator, setFlags, NULL, 0)
+ SPL_ME(MultipleIterator, attachIterator, arginfo_MultipleIterator_attachIterator, 0)
+ SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0)
+ SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0)
+ SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, NULL, 0)
+ /* Iterator */
+ SPL_ME(MultipleIterator, rewind, NULL, 0)
+ SPL_ME(MultipleIterator, valid, NULL, 0)
+ SPL_ME(MultipleIterator, key, NULL, 0)
+ SPL_ME(MultipleIterator, current, NULL, 0)
+ SPL_ME(MultipleIterator, next, NULL, 0)
+ {NULL, NULL, NULL}
+};
+
static const zend_function_entry spl_funcs_SplObjectStorage[] = {
SPL_ME(SplObjectStorage, attach, arginfo_attach, 0)
SPL_ME(SplObjectStorage, detach, arginfo_Object, 0)
REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess);
+ REGISTER_SPL_STD_CLASS_EX(MultipleIterator, spl_SplObjectStorage_new, spl_funcs_MultipleIterator);
+ REGISTER_SPL_ITERATOR(MultipleIterator);
+
+ REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ANY", MIT_NEED_ANY);
+ REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ALL", MIT_NEED_ALL);
+ REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_NUMERIC", MIT_KEYS_NUMERIC);
+ REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_ASSOC", MIT_KEYS_ASSOC);
+
return SUCCESS;
}
/* }}} */
--- /dev/null
+--TEST--
+SPL: MultipleIterator
+--FILE--
+<?php
+
+$iter1 = new ArrayIterator(array(1,2,3));
+$iter2 = new ArrayIterator(array(1,2));
+$iter3 = new ArrayIterator(array(new stdClass(),"string",3));
+
+$m = new MultipleIterator();
+
+echo "-- Default flags, no iterators --\n";
+foreach($m as $value) {
+ var_dump($value);
+}
+var_dump($m->current());
+
+$m->attachIterator($iter1);
+$m->attachIterator($iter2);
+$m->attachIterator($iter3);
+
+echo "-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC --\n";
+
+var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC));
+
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+try {
+ $m->current();
+} catch(RuntimeException $e) {
+ echo "RuntimeException thrown: " . $e->getMessage() . "\n";
+}
+try {
+ $m->key();
+} catch(RuntimeException $e) {
+ echo "RuntimeException thrown: " . $e->getMessage() . "\n";
+}
+
+echo "-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC --\n";
+
+$m->setFlags(MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC);
+var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC));
+
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+
+echo "-- Default flags, added element --\n";
+
+$m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC);
+
+$iter2[] = 3;
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+
+echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL --\n";
+
+$m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_ASSOC);
+$m->rewind();
+try {
+ $m->current();
+} catch(InvalidArgumentException $e) {
+ echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n";
+}
+
+echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC --\n";
+
+$m->attachIterator($iter1, "iter1");
+$m->attachIterator($iter2, b"iter2");
+$m->attachIterator($iter3, 3);
+
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+
+echo "-- Associate with invalid value --\n";
+
+try {
+ $m->attachIterator($iter3, new stdClass());
+} catch(InvalidArgumentException $e) {
+ echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n";
+}
+
+echo "-- Associate with duplicate value --\n";
+
+try {
+ $m->attachIterator($iter3, "iter1");
+} catch(InvalidArgumentException $e) {
+ echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n";
+}
+
+echo "-- Count, contains, detach, count, contains, iterate --\n";
+
+var_dump($m->countIterators());
+var_dump($m->containsIterator($iter2));
+var_dump($m->detachIterator($iter2));
+var_dump($m->countIterators());
+var_dump($m->containsIterator($iter2));
+foreach($m as $value) {
+ var_dump($m->key(), $value);
+}
+
+?>
+--EXPECTF--
+-- Default flags, no iterators --
+bool(false)
+-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC --
+bool(true)
+array(3) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(0)
+ [2]=>
+ int(0)
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ int(1)
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(2)
+ [2]=>
+ unicode(6) "string"
+}
+RuntimeException thrown: Called current() with non valid sub iterator
+RuntimeException thrown: Called key() with non valid sub iterator
+-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC --
+bool(true)
+array(3) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(0)
+ [2]=>
+ int(0)
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ int(1)
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(2)
+ [2]=>
+ unicode(6) "string"
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ NULL
+ [2]=>
+ int(2)
+}
+array(3) {
+ [0]=>
+ int(3)
+ [1]=>
+ NULL
+ [2]=>
+ int(3)
+}
+-- Default flags, added element --
+array(3) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(0)
+ [2]=>
+ int(0)
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ [2]=>
+ int(1)
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(2)
+ [2]=>
+ unicode(6) "string"
+}
+array(3) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(2)
+ [2]=>
+ int(2)
+}
+array(3) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(3)
+ [2]=>
+ int(3)
+}
+-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL --
+InvalidArgumentException thrown: Sub-Iterator is associated with NULL
+-- Flags |= MultipleIterator::MIT_KEYS_ASSOC --
+array(3) {
+ [u"iter1"]=>
+ int(0)
+ ["iter2"]=>
+ int(0)
+ [3]=>
+ int(0)
+}
+array(3) {
+ [u"iter1"]=>
+ int(1)
+ ["iter2"]=>
+ int(1)
+ [3]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(3) {
+ [u"iter1"]=>
+ int(1)
+ ["iter2"]=>
+ int(1)
+ [3]=>
+ int(1)
+}
+array(3) {
+ [u"iter1"]=>
+ int(2)
+ ["iter2"]=>
+ int(2)
+ [3]=>
+ unicode(6) "string"
+}
+array(3) {
+ [u"iter1"]=>
+ int(2)
+ ["iter2"]=>
+ int(2)
+ [3]=>
+ int(2)
+}
+array(3) {
+ [u"iter1"]=>
+ int(3)
+ ["iter2"]=>
+ int(3)
+ [3]=>
+ int(3)
+}
+-- Associate with invalid value --
+InvalidArgumentException thrown: Info must be NULL, integer or string
+-- Associate with duplicate value --
+InvalidArgumentException thrown: Key duplication error
+-- Count, contains, detach, count, contains, iterate --
+int(3)
+bool(true)
+NULL
+int(2)
+bool(false)
+array(2) {
+ [u"iter1"]=>
+ int(0)
+ [3]=>
+ int(0)
+}
+array(2) {
+ [u"iter1"]=>
+ int(1)
+ [3]=>
+ object(stdClass)#%d (0) {
+ }
+}
+array(2) {
+ [u"iter1"]=>
+ int(1)
+ [3]=>
+ int(1)
+}
+array(2) {
+ [u"iter1"]=>
+ int(2)
+ [3]=>
+ unicode(6) "string"
+}
+array(2) {
+ [u"iter1"]=>
+ int(2)
+ [3]=>
+ int(2)
+}
+array(2) {
+ [u"iter1"]=>
+ int(3)
+ [3]=>
+ int(3)
+}