mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
ext/spl: Restructure spl_array.c file to move ArrayObject methods together
This commit is contained in:
parent
1bdb0fddc1
commit
ba204a2e3a
1 changed files with 364 additions and 359 deletions
|
@ -33,13 +33,15 @@
|
||||||
#include "spl_array_arginfo.h"
|
#include "spl_array_arginfo.h"
|
||||||
#include "spl_exceptions.h"
|
#include "spl_exceptions.h"
|
||||||
|
|
||||||
zend_object_handlers spl_handler_ArrayObject;
|
/* Defined later in the file */
|
||||||
PHPAPI zend_class_entry *spl_ce_ArrayObject;
|
|
||||||
|
|
||||||
zend_object_handlers spl_handler_ArrayIterator;
|
zend_object_handlers spl_handler_ArrayIterator;
|
||||||
PHPAPI zend_class_entry *spl_ce_ArrayIterator;
|
PHPAPI zend_class_entry *spl_ce_ArrayIterator;
|
||||||
PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
|
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 {
|
typedef struct _spl_array_object {
|
||||||
zval array;
|
zval array;
|
||||||
uint32_t ht_iter;
|
uint32_t ht_iter;
|
||||||
|
@ -56,11 +58,6 @@ typedef struct _spl_array_object {
|
||||||
zend_object std;
|
zend_object std;
|
||||||
} spl_array_object;
|
} 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) /* {{{ */ {
|
static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ {
|
||||||
return (spl_array_object*)((char*)(obj) - XtOffsetOf(spl_array_object, std));
|
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;
|
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 */
|
/* {{{ 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) {
|
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 */
|
/* 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. */
|
/* {{{ Constructs a new array object from an array or object. */
|
||||||
PHP_METHOD(ArrayObject, __construct)
|
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. */
|
/* {{{ Set the class used in getIterator. */
|
||||||
PHP_METHOD(ArrayObject, setIteratorClass)
|
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) /* {{{ */
|
static zend_long spl_array_object_count_elements_helper(spl_array_object *intern) /* {{{ */
|
||||||
{
|
{
|
||||||
HashTable *aht = spl_array_get_hash_table(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. */
|
/* {{{ Sort the entries by key using case insensitive "natural order" algorithm. */
|
||||||
SPL_ARRAY_METHOD(ArrayObject, natcasesort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
|
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 */
|
/* {{{ Serialize the object */
|
||||||
PHP_METHOD(ArrayObject, serialize)
|
PHP_METHOD(ArrayObject, serialize)
|
||||||
{
|
{
|
||||||
|
@ -1866,6 +1512,365 @@ PHP_METHOD(ArrayObject, __debugInfo)
|
||||||
RETURN_ARR(spl_array_get_debug_info(Z_OBJ_P(ZEND_THIS)));
|
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) */
|
||||||
PHP_MINIT_FUNCTION(spl_array)
|
PHP_MINIT_FUNCTION(spl_array)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue