mirror of
https://github.com/php/php-src.git
synced 2024-09-22 10:27:25 +00:00
- Add MultipleIterator (Arnaud, Marcus)
This commit is contained in:
parent
0403ce45c6
commit
32f51050bc
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/** @file multipleiterator.inc
|
/** @file multipleiterator.inc
|
||||||
* @ingroup Examples
|
* @ingroup SPL
|
||||||
* @brief class MultipleIterator
|
* @brief class MultipleIterator
|
||||||
* @author Johannes Schlueter
|
* @author Johannes Schlueter
|
||||||
* @author Marcus Boerger
|
* @author Marcus Boerger
|
||||||
@ -9,7 +9,7 @@
|
|||||||
* SPL - Standard PHP Library
|
* SPL - Standard PHP Library
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @ingroup Examples
|
/** @ingroup SPL
|
||||||
* @brief Iterator that iterates over several iterators one after the other
|
* @brief Iterator that iterates over several iterators one after the other
|
||||||
* @author Johannes Schlueter
|
* @author Johannes Schlueter
|
||||||
* @author Marcus Boerger
|
* @author Marcus Boerger
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/** @file recursivetreeiterator.inc
|
/** @file recursivetreeiterator.inc
|
||||||
* @ingroup Examples
|
* @ingroup SPL
|
||||||
* @brief class RecursiveTreeIterator
|
* @brief class RecursiveTreeIterator
|
||||||
* @author Marcus Boerger, Johannes Schlueter
|
* @author Marcus Boerger, Johannes Schlueter
|
||||||
* @date 2005
|
* @date 2005
|
||||||
|
@ -150,14 +150,6 @@ PHP_FUNCTION(class_implements)
|
|||||||
SPL_ADD_CLASS(AppendIterator, z_list, sub, allow, ce_flags); \
|
SPL_ADD_CLASS(AppendIterator, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(ArrayIterator, 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(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(BadFunctionCallException, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(BadMethodCallException, 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(CachingIterator, z_list, sub, allow, ce_flags); \
|
||||||
@ -174,6 +166,7 @@ PHP_FUNCTION(class_implements)
|
|||||||
SPL_ADD_CLASS(LengthException, 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(LimitIterator, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(LogicException, 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(NoRewindIterator, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(OuterIterator, 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(OutOfBoundsException, z_list, sub, allow, ce_flags); \
|
||||||
@ -188,14 +181,23 @@ PHP_FUNCTION(class_implements)
|
|||||||
SPL_ADD_CLASS(RecursiveIterator, 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(RecursiveIteratorIterator, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(RecursiveRegexIterator, 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(RegexIterator, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(RuntimeException, 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(SeekableIterator, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(SimpleXMLIterator, 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(SplFileInfo, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(SplFileObject, 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(SplObjectStorage, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(SplObserver, 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(SplSubject, z_list, sub, allow, ce_flags); \
|
||||||
SPL_ADD_CLASS(SplTempFileObject, 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); \
|
SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "spl_directory.h"
|
#include "spl_directory.h"
|
||||||
#include "spl_array.h"
|
#include "spl_array.h"
|
||||||
#include "spl_exceptions.h"
|
#include "spl_exceptions.h"
|
||||||
|
#include "spl_observer.h"
|
||||||
#include "ext/standard/php_smart_str.h"
|
#include "ext/standard/php_smart_str.h"
|
||||||
|
|
||||||
#ifdef accept
|
#ifdef accept
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
extern PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
|
extern PHPAPI zend_class_entry *spl_ce_RecursiveIterator;
|
||||||
extern PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
|
extern PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator;
|
||||||
|
extern PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator;
|
||||||
extern PHPAPI zend_class_entry *spl_ce_FilterIterator;
|
extern PHPAPI zend_class_entry *spl_ce_FilterIterator;
|
||||||
extern PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
|
extern PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator;
|
||||||
extern PHPAPI zend_class_entry *spl_ce_ParentIterator;
|
extern PHPAPI zend_class_entry *spl_ce_ParentIterator;
|
||||||
|
@ -73,6 +73,8 @@ static const zend_function_entry spl_funcs_SplSubject[] = {
|
|||||||
PHPAPI zend_class_entry *spl_ce_SplObserver;
|
PHPAPI zend_class_entry *spl_ce_SplObserver;
|
||||||
PHPAPI zend_class_entry *spl_ce_SplSubject;
|
PHPAPI zend_class_entry *spl_ce_SplSubject;
|
||||||
PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
|
PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
|
||||||
|
PHPAPI zend_class_entry *spl_ce_MultipleIterator;
|
||||||
|
|
||||||
PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
|
PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
|
||||||
|
|
||||||
typedef struct _spl_SplObjectStorage { /* {{{ */
|
typedef struct _spl_SplObjectStorage { /* {{{ */
|
||||||
@ -80,6 +82,7 @@ typedef struct _spl_SplObjectStorage { /* {{{ */
|
|||||||
HashTable storage;
|
HashTable storage;
|
||||||
long index;
|
long index;
|
||||||
HashPosition pos;
|
HashPosition pos;
|
||||||
|
long flags;
|
||||||
} spl_SplObjectStorage; /* }}} */
|
} spl_SplObjectStorage; /* }}} */
|
||||||
|
|
||||||
/* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */
|
/* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */
|
||||||
@ -595,6 +598,298 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
|
|||||||
ZEND_ARG_INFO(0, info)
|
ZEND_ARG_INFO(0, info)
|
||||||
ZEND_END_ARG_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[] = {
|
static const zend_function_entry spl_funcs_SplObjectStorage[] = {
|
||||||
SPL_ME(SplObjectStorage, attach, arginfo_attach, 0)
|
SPL_ME(SplObjectStorage, attach, arginfo_attach, 0)
|
||||||
SPL_ME(SplObjectStorage, detach, arginfo_Object, 0)
|
SPL_ME(SplObjectStorage, detach, arginfo_Object, 0)
|
||||||
@ -635,6 +930,14 @@ PHP_MINIT_FUNCTION(spl_observer)
|
|||||||
REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
|
REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
|
||||||
REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess);
|
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;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
extern PHPAPI zend_class_entry *spl_ce_SplObserver;
|
extern PHPAPI zend_class_entry *spl_ce_SplObserver;
|
||||||
extern PHPAPI zend_class_entry *spl_ce_SplSubject;
|
extern PHPAPI zend_class_entry *spl_ce_SplSubject;
|
||||||
extern PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
|
extern PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
|
||||||
|
extern PHPAPI zend_class_entry *spl_ce_MultipleIterator;
|
||||||
|
|
||||||
PHP_MINIT_FUNCTION(spl_observer);
|
PHP_MINIT_FUNCTION(spl_observer);
|
||||||
|
|
||||||
|
345
ext/spl/tests/multiple_iterator_001.phpt
Executable file
345
ext/spl/tests/multiple_iterator_001.phpt
Executable file
@ -0,0 +1,345 @@
|
|||||||
|
--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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user