helly Sat Jul 19 21:22:04 2003 EDT
Added files:
/spl/tests array_iterator.phpt
Modified files:
/spl spl_array.c
Log:
- Add class spl_array_it which is the iterator returned by spl_array.
This class can also be used alone without spl_array but doesn't allow
recursive foreach usage.
- Fix protos to new proto system.
- Add test for spl_array_it.
Index: spl/spl_array.c
diff -u spl/spl_array.c:1.9 spl/spl_array.c:1.10
--- spl/spl_array.c:1.9 Sat Jul 19 16:54:22 2003
+++ spl/spl_array.c Sat Jul 19 21:22:03 2003
@@ -241,6 +241,7 @@
/* }}} */
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);
@@ -249,6 +250,12 @@
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)
SPL_CLASS_FE(array, key, NULL)
@@ -258,7 +265,10 @@
};
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;
@@ -309,7 +319,11 @@
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;
}
/* }}} */
@@ -348,6 +362,13 @@
}
/* }}} */
+/* {{{ 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)
{
@@ -434,7 +455,7 @@
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;
@@ -442,11 +463,17 @@
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)
{
@@ -480,26 +507,86 @@
}
/* }}} */
-/* {{{ 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;
@@ -507,7 +594,7 @@
}
/* }}} */
-/* {{{ proto string key()
+/* {{{ proto mixed|false spl_array_it::key()
Return current array key */
SPL_CLASS_FUNCTION(array, key)
{
@@ -516,8 +603,19 @@
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;
@@ -530,25 +628,46 @@
}
/* }}} */
-/* {{{ 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);
+ }
}
/* }}} */
Index: spl/tests/array_iterator.phpt
+++ spl/tests/array_iterator.phpt
--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
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php