/* }}} */
SPL_CLASS_FUNCTION(array, __construct);
+SPL_CLASS_FUNCTION(array, new_iterator);
SPL_CLASS_FUNCTION(array, rewind);
SPL_CLASS_FUNCTION(array, current);
SPL_CLASS_FUNCTION(array, key);
SPL_CLASS_FUNCTION(array, has_more);
static zend_function_entry spl_array_class_functions[] = {
+ SPL_CLASS_FE(array, __construct, NULL)
+ SPL_CLASS_FE(array, new_iterator, NULL)
+ {NULL, NULL, NULL}
+};
+
+static zend_function_entry spl_array_it_class_functions[] = {
SPL_CLASS_FE(array, __construct, NULL)
SPL_CLASS_FE(array, rewind, NULL)
SPL_CLASS_FE(array, current, NULL)
};
static zend_object_handlers spl_array_handlers;
-static zend_class_entry *spl_ce_array;
+static zend_class_entry * spl_ce_array;
+
+static zend_object_handlers spl_array_it_handlers;
+static zend_class_entry * spl_ce_array_it;
typedef struct _spl_array_object {
zend_object std;
zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos);
retval.handle = zend_objects_store_put(intern, spl_array_object_dtor, NULL TSRMLS_CC);
- retval.handlers = &spl_array_handlers;
+ if (class_type == spl_ce_array_it) {
+ retval.handlers = &spl_array_it_handlers;
+ } else {
+ retval.handlers = &spl_array_handlers;
+ }
return retval;
}
/* }}} */
}
/* }}} */
+/* {{{ spl_array_get_ce */
+static zend_class_entry *spl_array_it_get_ce(zval *object TSRMLS_DC)
+{
+ return spl_ce_array_it;
+}
+/* }}} */
+
/* {{{ spl_array_read_dimension */
zval *spl_array_read_dimension(zval *object, zval *offset TSRMLS_DC)
{
PHP_MINIT_FUNCTION(spl_array)
{
REGISTER_SPL_STD_CLASS_EX(array, spl_array_object_new, spl_array_class_functions);
- REGISTER_SPL_IMPLEMENT(array, sequence_assoc);
+ REGISTER_SPL_IMPLEMENT(array, iterator);
memcpy(&spl_array_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
spl_array_handlers.clone_obj = spl_array_object_clone;
spl_array_handlers.get_class_entry = spl_array_get_ce;
spl_array_handlers.write_dimension = spl_array_write_dimension;
spl_array_handlers.get_properties = spl_array_get_properties;
+ REGISTER_SPL_STD_CLASS_EX(array_it, spl_array_object_new, spl_array_it_class_functions);
+ REGISTER_SPL_IMPLEMENT(array_it, sequence_assoc);
+ memcpy(&spl_array_it_handlers, &spl_array_handlers, sizeof(zend_object_handlers));
+ spl_array_it_handlers.get_class_entry = spl_array_it_get_ce;
+
return SUCCESS;
}
/* }}} */
-/* {{{ proto void __construct(array ar = array())
+/* {{{ proto void spl_array::__construct(array ar = array())
+ proto void spl_array_it::__construct(array ar = array())
Cronstructs a new array iterator from a path. */
SPL_CLASS_FUNCTION(array, __construct)
{
}
/* }}} */
-/* {{{ proto void rewind()
+/* {{{ proto spl_array_it|NULL spl_array::new_iterator()
+ Create a new iterator from a spl_array instance */
+SPL_CLASS_FUNCTION(array, new_iterator)
+{
+ zval *object = getThis();
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ spl_array_object *iterator;
+ HashTable *aht = HASH_OF(intern->array);
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = spl_array_object_new_ex(spl_ce_array_it, &iterator, intern TSRMLS_CC);
+ return_value->refcount = 1;
+ return_value->is_ref = 1;
+}
+/* }}} */
+
+/* {{{ spl_hash_pos_exists */
+ZEND_API int spl_hash_pos_exists(spl_array_object * intern TSRMLS_DC)
+{
+ HashTable *ht = HASH_OF(intern->array);
+ Bucket *p;
+
+/* IS_CONSISTENT(ht);*/
+
+/* HASH_PROTECT_RECURSION(ht);*/
+ p = ht->pListHead;
+ while (p != NULL) {
+ if (p == intern->pos) {
+ return SUCCESS;
+ }
+ p = p->pListNext;
+ }
+/* HASH_UNPROTECT_RECURSION(ht); */
+ zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos);
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ proto void spl_array_it::rewind()
Rewind array back to the start */
SPL_CLASS_FUNCTION(array, rewind)
{
zval *object = getThis();
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = HASH_OF(intern->array);
- zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos);
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
}
/* }}} */
-/* {{{ proto string current()
+/* {{{ proto mixed|false spl_array_it::current()
Return current array entry */
SPL_CLASS_FUNCTION(array, current)
{
zval *object = getThis();
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
zval **entry;
+ HashTable *aht = HASH_OF(intern->array);
- if (zend_hash_get_current_data_ex(HASH_OF(intern->array), (void **) &entry, &intern->pos) == FAILURE) {
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
+ RETURN_FALSE;
+ }
+
+ if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
RETURN_FALSE;
}
*return_value = **entry;
}
/* }}} */
-/* {{{ proto string key()
+/* {{{ proto mixed|false spl_array_it::key()
Return current array key */
SPL_CLASS_FUNCTION(array, key)
{
char *string_key;
uint string_length;
ulong num_key;
+ HashTable *aht = HASH_OF(intern->array);
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
- switch (zend_hash_get_current_key_ex(HASH_OF(intern->array), &string_key, &string_length, &num_key, 0, &intern->pos)) {
+ if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
+ RETURN_FALSE;
+ }
+
+ switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos)) {
case HASH_KEY_IS_STRING:
RETVAL_STRINGL(string_key, string_length - 1, 1);
break;
}
/* }}} */
-/* {{{ proto void next()
+/* {{{ proto void spl_array_it::next()
Move to next entry */
SPL_CLASS_FUNCTION(array, next)
{
zval *object = getThis();
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = HASH_OF(intern->array);
- zend_hash_move_forward_ex(HASH_OF(intern->array), &intern->pos);
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
+ } else {
+ zend_hash_move_forward_ex(aht, &intern->pos);
+ }
}
/* }}} */
-/* {{{ proto string has_more()
+/* {{{ proto bool spl_array_it::has_more()
Check whether array contains more entries */
SPL_CLASS_FUNCTION(array, has_more)
{
zval *object = getThis();
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ HashTable *aht = HASH_OF(intern->array);
+
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
+ return;
+ }
- RETURN_BOOL(zend_hash_has_more_elements_ex(HASH_OF(intern->array), &intern->pos) == SUCCESS);
+ if (intern->pos && intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
+ RETURN_FALSE;
+ } else {
+ RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
+ }
}
/* }}} */
--- /dev/null
+--TEST--
+SPL: spl_array_iterator
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+echo "==Normal==\n";
+
+$arr = array(0=>0, 1=>1, 2=>2);
+$obj = new spl_array($arr);
+
+foreach($obj as $ak=>$av) {
+ foreach($obj as $bk=>$bv) {
+ if ($ak==0 && $bk==0) {
+ $arr[0] = "modify";
+ }
+ echo "$ak=>$av - $bk=>$bv\n";
+ }
+}
+
+echo "==UseRef==\n";
+
+$arr = array(0=>0, 1=>1, 2=>2);
+$obj = new spl_array(&$arr);
+
+foreach($obj as $ak=>$av) {
+ foreach($obj as $bk=>$bv) {
+ echo "$ak=>$av - $bk=>$bv\n";
+ }
+}
+
+echo "==Modify==\n";
+
+$arr = array(0=>0, 1=>1, 2=>2);
+$obj = new spl_array(&$arr);
+
+foreach($obj as $ak=>$av) {
+ foreach($obj as $bk=>$bv) {
+ if ($ak==0 && $bk==0) {
+ $arr[0] = "modify";
+ }
+ echo "$ak=>$av - $bk=>$bv\n";
+ }
+}
+
+echo "==Delete==\n";
+
+$arr = array(0=>0, 1=>1, 2=>2);
+$obj = new spl_array(&$arr);
+
+foreach($obj as $ak=>$av) {
+ foreach($obj as $bk=>$bv) {
+ if ($ak==1 && $bk==1) {
+ unset($arr[1]);
+ }
+ echo "$ak=>$av - $bk=>$bv\n";
+ }
+}
+
+echo "==Change==\n";
+
+$arr = array(0=>0, 1=>1, 2=>2);
+$obj = new spl_array(&$arr);
+
+foreach($obj as $ak=>$av) {
+ foreach($obj as $bk=>$bv) {
+ if ($ak==1 && $bk==1) {
+ $arr = NULL;
+ }
+ echo "$ak=>$av - $bk=>$bv\n";
+ }
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+==Normal==
+0=>0 - 0=>0
+0=>0 - 1=>1
+0=>0 - 2=>2
+1=>1 - 0=>0
+1=>1 - 1=>1
+1=>1 - 2=>2
+2=>2 - 0=>0
+2=>2 - 1=>1
+2=>2 - 2=>2
+==UseRef==
+0=>0 - 0=>0
+0=>0 - 1=>1
+0=>0 - 2=>2
+1=>1 - 0=>0
+1=>1 - 1=>1
+1=>1 - 2=>2
+2=>2 - 0=>0
+2=>2 - 1=>1
+2=>2 - 2=>2
+==Modify==
+0=>0 - 0=>0
+0=>0 - 1=>1
+0=>0 - 2=>2
+1=>1 - 0=>modify
+1=>1 - 1=>1
+1=>1 - 2=>2
+2=>2 - 0=>modify
+2=>2 - 1=>1
+2=>2 - 2=>2
+==Delete==
+0=>0 - 0=>0
+0=>0 - 1=>1
+0=>0 - 2=>2
+1=>1 - 0=>0
+1=>1 - 1=>1
+
+Notice: next(): Array was modified outside object and internal position is no longer valid in %sarray_iterator.php on line %d
+1=>1 - 0=>0
+1=>1 - 2=>2
+
+Notice: next(): Array was modified outside object and internal position is no longer valid in %sarray_iterator.php on line %d
+0=>0 - 0=>0
+0=>0 - 2=>2
+2=>2 - 0=>0
+2=>2 - 2=>2
+==Change==
+0=>0 - 0=>0
+0=>0 - 1=>1
+0=>0 - 2=>2
+1=>1 - 0=>0
+1=>1 - 1=>1
+
+Notice: next(): Array was modified outside object and is no longer an array in %sarray_iterator.php on line %d
+
+Notice: has_more(): Array was modified outside object and is no longer an array in %sarray_iterator.php on line %d
+
+Notice: next(): Array was modified outside object and is no longer an array in %sarray_iterator.php on line %d
+
+Notice: has_more(): Array was modified outside object and is no longer an array in %sarray_iterator.php on line %d
+Done