ext/spl: Restructure spl_array.c file to move ArrayObject methods together

This commit is contained in:
George Peter Banyard 2023-08-22 15:49:02 +01:00 committed by Gina Peter Banyard
parent 1bdb0fddc1
commit ba204a2e3a
No known key found for this signature in database
GPG Key ID: 3306078E3194AEBD

View File

@ -33,13 +33,15 @@
#include "spl_array_arginfo.h"
#include "spl_exceptions.h"
zend_object_handlers spl_handler_ArrayObject;
PHPAPI zend_class_entry *spl_ce_ArrayObject;
/* Defined later in the file */
zend_object_handlers spl_handler_ArrayIterator;
PHPAPI zend_class_entry *spl_ce_ArrayIterator;
PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
/* ArrayObject class */
zend_object_handlers spl_handler_ArrayObject;
PHPAPI zend_class_entry *spl_ce_ArrayObject;
typedef struct _spl_array_object {
zval array;
uint32_t ht_iter;
@ -56,11 +58,6 @@ typedef struct _spl_array_object {
zend_object std;
} spl_array_object;
typedef struct _spl_array_iterator {
zend_object_iterator it;
bool by_ref;
} spl_array_iterator;
static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ {
return (spl_array_object*)((char*)(obj) - XtOffsetOf(spl_array_object, std));
}
@ -935,118 +932,6 @@ static zend_result spl_array_skip_protected(spl_array_object *intern, HashTable
return FAILURE;
} /* }}} */
static zend_result spl_array_next_ex(spl_array_object *intern, HashTable *aht) /* {{{ */
{
uint32_t *pos_ptr = spl_array_get_pos_ptr(aht, intern);
zend_hash_move_forward_ex(aht, pos_ptr);
if (spl_array_is_object(intern)) {
return spl_array_skip_protected(intern, aht);
} else {
return zend_hash_has_more_elements_ex(aht, pos_ptr);
}
} /* }}} */
static zend_result spl_array_next(spl_array_object *intern) /* {{{ */
{
HashTable *aht = spl_array_get_hash_table(intern);
return spl_array_next_ex(intern, aht);
} /* }}} */
static void spl_array_it_dtor(zend_object_iterator *iter) /* {{{ */
{
zval_ptr_dtor(&iter->data);
}
/* }}} */
static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
HashTable *aht = spl_array_get_hash_table(object);
return zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, object));
}
/* }}} */
static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */
{
spl_array_iterator *array_iter = (spl_array_iterator*)iter;
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
HashTable *aht = spl_array_get_hash_table(object);
zval *data = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, object));
if (data && Z_TYPE_P(data) == IS_INDIRECT) {
data = Z_INDIRECT_P(data);
}
// ZEND_FE_FETCH_RW converts the value to a reference but doesn't know the source is a property.
// Typed properties must add a type source to the reference, and readonly properties must fail.
if (array_iter->by_ref
&& Z_TYPE_P(data) != IS_REFERENCE
&& Z_TYPE(object->array) == IS_OBJECT
&& !(object->ar_flags & (SPL_ARRAY_IS_SELF|SPL_ARRAY_USE_OTHER))) {
zend_string *key;
zend_hash_get_current_key_ex(aht, &key, NULL, spl_array_get_pos_ptr(aht, object));
zend_class_entry *ce = Z_OBJCE(object->array);
zend_property_info *prop_info = zend_get_property_info(ce, key, true);
ZEND_ASSERT(prop_info != ZEND_WRONG_PROPERTY_INFO);
if (EXPECTED(prop_info != NULL) && ZEND_TYPE_IS_SET(prop_info->type)) {
if (prop_info->flags & ZEND_ACC_READONLY) {
zend_throw_error(NULL,
"Cannot acquire reference to readonly property %s::$%s",
ZSTR_VAL(prop_info->ce->name), ZSTR_VAL(key));
return NULL;
}
ZVAL_NEW_REF(data, data);
ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), prop_info);
}
}
return data;
}
/* }}} */
static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
HashTable *aht = spl_array_get_hash_table(object);
zend_hash_get_current_key_zval_ex(aht, key, spl_array_get_pos_ptr(aht, object));
}
/* }}} */
static void spl_array_it_move_forward(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
HashTable *aht = spl_array_get_hash_table(object);
spl_array_next_ex(object, aht);
}
/* }}} */
static void spl_array_rewind(spl_array_object *intern) /* {{{ */
{
HashTable *aht = spl_array_get_hash_table(intern);
if (intern->ht_iter == (uint32_t)-1) {
spl_array_get_pos_ptr(aht, intern);
} else {
zend_hash_internal_pointer_reset_ex(aht, spl_array_get_pos_ptr(aht, intern));
spl_array_skip_protected(intern, aht);
}
}
/* }}} */
static void spl_array_it_rewind(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
spl_array_rewind(object);
}
/* }}} */
static HashTable *spl_array_it_get_gc(zend_object_iterator *iter, zval **table, int *n)
{
*n = 1;
*table = &iter->data;
return NULL;
}
/* {{{ spl_array_set_array */
static void spl_array_set_array(zval *object, spl_array_object *intern, zval *array, zend_long ar_flags, bool just_array) {
/* Handled by ZPP prior to this, or for __unserialize() before passing to here */
@ -1104,31 +989,6 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
}
/* }}} */
/* iterator handler table */
static const zend_object_iterator_funcs spl_array_it_funcs = {
spl_array_it_dtor,
spl_array_it_valid,
spl_array_it_get_current_data,
spl_array_it_get_current_key,
spl_array_it_move_forward,
spl_array_it_rewind,
NULL,
spl_array_it_get_gc,
};
static zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
{
spl_array_iterator *iterator = emalloc(sizeof(spl_array_iterator));
zend_iterator_init(&iterator->it);
ZVAL_OBJ_COPY(&iterator->it.data, Z_OBJ_P(object));
iterator->it.funcs = &spl_array_it_funcs;
iterator->by_ref = by_ref;
return &iterator->it;
}
/* }}} */
/* {{{ Constructs a new array object from an array or object. */
PHP_METHOD(ArrayObject, __construct)
{
@ -1158,30 +1018,6 @@ PHP_METHOD(ArrayObject, __construct)
}
/* }}} */
/* {{{ Constructs a new array iterator from an array or object. */
PHP_METHOD(ArrayIterator, __construct)
{
zval *object = ZEND_THIS;
spl_array_object *intern;
zval *array;
zend_long ar_flags = 0;
if (ZEND_NUM_ARGS() == 0) {
return; /* nothing to do */
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Al", &array, &ar_flags) == FAILURE) {
RETURN_THROWS();
}
intern = Z_SPLARRAY_P(object);
ar_flags &= ~SPL_ARRAY_INT_MASK;
spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1);
}
/* }}} */
/* {{{ Set the class used in getIterator. */
PHP_METHOD(ArrayObject, setIteratorClass)
{
@ -1275,48 +1111,6 @@ PHP_METHOD(ArrayObject, getIterator)
}
/* }}} */
/* {{{ Rewind array back to the start */
PHP_METHOD(ArrayIterator, rewind)
{
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
spl_array_rewind(intern);
}
/* }}} */
/* {{{ Seek to position. */
PHP_METHOD(ArrayIterator, seek)
{
zend_long opos, position;
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
int result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) {
RETURN_THROWS();
}
opos = position;
if (position >= 0) { /* negative values are not supported */
spl_array_rewind(intern);
result = SUCCESS;
while (position-- > 0 && (result = spl_array_next(intern)) == SUCCESS);
if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS) {
return; /* ok */
}
}
zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", opos);
} /* }}} */
static zend_long spl_array_object_count_elements_helper(spl_array_object *intern) /* {{{ */
{
HashTable *aht = spl_array_get_hash_table(intern);
@ -1445,154 +1239,6 @@ SPL_ARRAY_METHOD(ArrayObject, natsort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
/* {{{ Sort the entries by key using case insensitive "natural order" algorithm. */
SPL_ARRAY_METHOD(ArrayObject, natcasesort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
/* {{{ Return current array entry */
PHP_METHOD(ArrayIterator, current)
{
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
zval *entry;
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
RETURN_NULL();
}
if (Z_TYPE_P(entry) == IS_INDIRECT) {
entry = Z_INDIRECT_P(entry);
if (Z_TYPE_P(entry) == IS_UNDEF) {
RETURN_NULL();
}
}
RETURN_COPY_DEREF(entry);
}
/* }}} */
/* {{{ Return current array key */
PHP_METHOD(ArrayIterator, key)
{
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
spl_array_iterator_key(ZEND_THIS, return_value);
} /* }}} */
void spl_array_iterator_key(zval *object, zval *return_value) /* {{{ */
{
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
zend_hash_get_current_key_zval_ex(aht, return_value, spl_array_get_pos_ptr(aht, intern));
}
/* }}} */
/* {{{ Move to next entry */
PHP_METHOD(ArrayIterator, next)
{
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
spl_array_next_ex(intern, aht);
}
/* }}} */
/* {{{ Check whether array contains more entries */
PHP_METHOD(ArrayIterator, valid)
{
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
RETURN_BOOL(zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS);
}
/* }}} */
/* {{{ Check whether current element has children (e.g. is an array) */
PHP_METHOD(RecursiveArrayIterator, hasChildren)
{
zval *object = ZEND_THIS, *entry;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
RETURN_FALSE;
}
if (Z_TYPE_P(entry) == IS_INDIRECT) {
entry = Z_INDIRECT_P(entry);
}
ZVAL_DEREF(entry);
RETURN_BOOL(Z_TYPE_P(entry) == IS_ARRAY || (Z_TYPE_P(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
}
/* }}} */
static void spl_instantiate_child_arg(zend_class_entry *pce, zval *retval, zval *arg1, zval *arg2) /* {{{ */
{
object_init_ex(retval, pce);
spl_array_object *new_intern = Z_SPLARRAY_P(retval);
/*
* set new_intern->is_child is true to indicate that the object was created by
* RecursiveArrayIterator::getChildren() method.
*/
new_intern->is_child = true;
/* find the bucket of parent object. */
new_intern->bucket = (Bucket *)((char *)(arg1) - XtOffsetOf(Bucket, val));;
zend_call_known_instance_method_with_2_params(pce->constructor, Z_OBJ_P(retval), NULL, arg1, arg2);
}
/* }}} */
/* {{{ Create a sub iterator for the current element (same class as $this) */
PHP_METHOD(RecursiveArrayIterator, getChildren)
{
zval *object = ZEND_THIS, *entry, flags;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
RETURN_NULL();
}
if (Z_TYPE_P(entry) == IS_INDIRECT) {
entry = Z_INDIRECT_P(entry);
}
ZVAL_DEREF(entry);
if (Z_TYPE_P(entry) == IS_OBJECT) {
if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
RETURN_NULL();
}
if (instanceof_function(Z_OBJCE_P(entry), Z_OBJCE_P(ZEND_THIS))) {
RETURN_OBJ_COPY(Z_OBJ_P(entry));
}
}
ZVAL_LONG(&flags, intern->ar_flags);
spl_instantiate_child_arg(Z_OBJCE_P(ZEND_THIS), return_value, entry, &flags);
}
/* }}} */
/* {{{ Serialize the object */
PHP_METHOD(ArrayObject, serialize)
{
@ -1866,6 +1512,365 @@ PHP_METHOD(ArrayObject, __debugInfo)
RETURN_ARR(spl_array_get_debug_info(Z_OBJ_P(ZEND_THIS)));
} /* }}} */
/*** ArrayIterator class ***/
typedef struct _spl_array_iterator {
zend_object_iterator it;
bool by_ref;
} spl_array_iterator;
static zend_result spl_array_next_ex(spl_array_object *intern, HashTable *aht) /* {{{ */
{
uint32_t *pos_ptr = spl_array_get_pos_ptr(aht, intern);
zend_hash_move_forward_ex(aht, pos_ptr);
if (spl_array_is_object(intern)) {
return spl_array_skip_protected(intern, aht);
} else {
return zend_hash_has_more_elements_ex(aht, pos_ptr);
}
} /* }}} */
static zend_result spl_array_next(spl_array_object *intern) /* {{{ */
{
HashTable *aht = spl_array_get_hash_table(intern);
return spl_array_next_ex(intern, aht);
} /* }}} */
static void spl_array_it_dtor(zend_object_iterator *iter) /* {{{ */
{
zval_ptr_dtor(&iter->data);
}
/* }}} */
static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
HashTable *aht = spl_array_get_hash_table(object);
return zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, object));
}
/* }}} */
static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */
{
spl_array_iterator *array_iter = (spl_array_iterator*)iter;
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
HashTable *aht = spl_array_get_hash_table(object);
zval *data = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, object));
if (data && Z_TYPE_P(data) == IS_INDIRECT) {
data = Z_INDIRECT_P(data);
}
// ZEND_FE_FETCH_RW converts the value to a reference but doesn't know the source is a property.
// Typed properties must add a type source to the reference, and readonly properties must fail.
if (array_iter->by_ref
&& Z_TYPE_P(data) != IS_REFERENCE
&& Z_TYPE(object->array) == IS_OBJECT
&& !(object->ar_flags & (SPL_ARRAY_IS_SELF|SPL_ARRAY_USE_OTHER))) {
zend_string *key;
zend_hash_get_current_key_ex(aht, &key, NULL, spl_array_get_pos_ptr(aht, object));
zend_class_entry *ce = Z_OBJCE(object->array);
zend_property_info *prop_info = zend_get_property_info(ce, key, true);
ZEND_ASSERT(prop_info != ZEND_WRONG_PROPERTY_INFO);
if (EXPECTED(prop_info != NULL) && ZEND_TYPE_IS_SET(prop_info->type)) {
if (prop_info->flags & ZEND_ACC_READONLY) {
zend_throw_error(NULL,
"Cannot acquire reference to readonly property %s::$%s",
ZSTR_VAL(prop_info->ce->name), ZSTR_VAL(key));
return NULL;
}
ZVAL_NEW_REF(data, data);
ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), prop_info);
}
}
return data;
}
/* }}} */
static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
HashTable *aht = spl_array_get_hash_table(object);
zend_hash_get_current_key_zval_ex(aht, key, spl_array_get_pos_ptr(aht, object));
}
/* }}} */
static void spl_array_it_move_forward(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
HashTable *aht = spl_array_get_hash_table(object);
spl_array_next_ex(object, aht);
}
/* }}} */
static void spl_array_rewind(spl_array_object *intern) /* {{{ */
{
HashTable *aht = spl_array_get_hash_table(intern);
if (intern->ht_iter == (uint32_t)-1) {
spl_array_get_pos_ptr(aht, intern);
} else {
zend_hash_internal_pointer_reset_ex(aht, spl_array_get_pos_ptr(aht, intern));
spl_array_skip_protected(intern, aht);
}
}
/* }}} */
static void spl_array_it_rewind(zend_object_iterator *iter) /* {{{ */
{
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
spl_array_rewind(object);
}
/* }}} */
static HashTable *spl_array_it_get_gc(zend_object_iterator *iter, zval **table, int *n)
{
*n = 1;
*table = &iter->data;
return NULL;
}
/* iterator handler table */
static const zend_object_iterator_funcs spl_array_it_funcs = {
spl_array_it_dtor,
spl_array_it_valid,
spl_array_it_get_current_data,
spl_array_it_get_current_key,
spl_array_it_move_forward,
spl_array_it_rewind,
NULL,
spl_array_it_get_gc,
};
static zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
{
spl_array_iterator *iterator = emalloc(sizeof(spl_array_iterator));
zend_iterator_init(&iterator->it);
ZVAL_OBJ_COPY(&iterator->it.data, Z_OBJ_P(object));
iterator->it.funcs = &spl_array_it_funcs;
iterator->by_ref = by_ref;
return &iterator->it;
}
/* }}} */
/* {{{ Constructs a new array iterator from an array or object. */
PHP_METHOD(ArrayIterator, __construct)
{
zval *object = ZEND_THIS;
spl_array_object *intern;
zval *array;
zend_long ar_flags = 0;
if (ZEND_NUM_ARGS() == 0) {
return; /* nothing to do */
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Al", &array, &ar_flags) == FAILURE) {
RETURN_THROWS();
}
intern = Z_SPLARRAY_P(object);
ar_flags &= ~SPL_ARRAY_INT_MASK;
spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1);
}
/* }}} */
/* {{{ Rewind array back to the start */
PHP_METHOD(ArrayIterator, rewind)
{
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
spl_array_rewind(intern);
}
/* }}} */
/* {{{ Seek to position. */
PHP_METHOD(ArrayIterator, seek)
{
zend_long opos, position;
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
int result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) {
RETURN_THROWS();
}
opos = position;
if (position >= 0) { /* negative values are not supported */
spl_array_rewind(intern);
result = SUCCESS;
while (position-- > 0 && (result = spl_array_next(intern)) == SUCCESS);
if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS) {
return; /* ok */
}
}
zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", opos);
} /* }}} */
/* {{{ Return current array entry */
PHP_METHOD(ArrayIterator, current)
{
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
zval *entry;
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
RETURN_NULL();
}
if (Z_TYPE_P(entry) == IS_INDIRECT) {
entry = Z_INDIRECT_P(entry);
if (Z_TYPE_P(entry) == IS_UNDEF) {
RETURN_NULL();
}
}
RETURN_COPY_DEREF(entry);
}
/* }}} */
void spl_array_iterator_key(zval *object, zval *return_value) /* {{{ */
{
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
zend_hash_get_current_key_zval_ex(aht, return_value, spl_array_get_pos_ptr(aht, intern));
}
/* }}} */
/* {{{ Return current array key */
PHP_METHOD(ArrayIterator, key)
{
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
spl_array_iterator_key(ZEND_THIS, return_value);
} /* }}} */
/* {{{ Move to next entry */
PHP_METHOD(ArrayIterator, next)
{
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
spl_array_next_ex(intern, aht);
}
/* }}} */
/* {{{ Check whether array contains more entries */
PHP_METHOD(ArrayIterator, valid)
{
zval *object = ZEND_THIS;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
RETURN_BOOL(zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS);
}
/* }}} */
/*** RecursiveArrayIterator methods ***/
/* {{{ Check whether current element has children (e.g. is an array) */
PHP_METHOD(RecursiveArrayIterator, hasChildren)
{
zval *object = ZEND_THIS, *entry;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
RETURN_FALSE;
}
if (Z_TYPE_P(entry) == IS_INDIRECT) {
entry = Z_INDIRECT_P(entry);
}
ZVAL_DEREF(entry);
RETURN_BOOL(Z_TYPE_P(entry) == IS_ARRAY || (Z_TYPE_P(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
}
/* }}} */
static void spl_instantiate_child_arg(zend_class_entry *pce, zval *retval, zval *arg1, zval *arg2) /* {{{ */
{
object_init_ex(retval, pce);
spl_array_object *new_intern = Z_SPLARRAY_P(retval);
/*
* set new_intern->is_child is true to indicate that the object was created by
* RecursiveArrayIterator::getChildren() method.
*/
new_intern->is_child = true;
/* find the bucket of parent object. */
new_intern->bucket = (Bucket *)((char *)(arg1) - XtOffsetOf(Bucket, val));;
zend_call_known_instance_method_with_2_params(pce->constructor, Z_OBJ_P(retval), NULL, arg1, arg2);
}
/* }}} */
/* {{{ Create a sub iterator for the current element (same class as $this) */
PHP_METHOD(RecursiveArrayIterator, getChildren)
{
zval *object = ZEND_THIS, *entry, flags;
spl_array_object *intern = Z_SPLARRAY_P(object);
HashTable *aht = spl_array_get_hash_table(intern);
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
RETURN_NULL();
}
if (Z_TYPE_P(entry) == IS_INDIRECT) {
entry = Z_INDIRECT_P(entry);
}
ZVAL_DEREF(entry);
if (Z_TYPE_P(entry) == IS_OBJECT) {
if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
RETURN_NULL();
}
if (instanceof_function(Z_OBJCE_P(entry), Z_OBJCE_P(ZEND_THIS))) {
RETURN_OBJ_COPY(Z_OBJ_P(entry));
}
}
ZVAL_LONG(&flags, intern->ar_flags);
spl_instantiate_child_arg(Z_OBJCE_P(ZEND_THIS), return_value, entry, &flags);
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION(spl_array) */
PHP_MINIT_FUNCTION(spl_array)
{