]> granicus.if.org Git - php/commitdiff
Major update:
authorMarcus Boerger <helly@php.net>
Sun, 9 Nov 2003 14:05:36 +0000 (14:05 +0000)
committerMarcus Boerger <helly@php.net>
Sun, 9 Nov 2003 14:05:36 +0000 (14:05 +0000)
- Remove all overloading hooks -> array_read/array_access must be rewritten
- Remove all basic iterators
- Remove all 'spl_' prefixing exposed to user level
- Add RecursiveIterator, RecursiveIteratorIterator
- Add DirectoryIterator, DirectoryTreeIterator
- Add some examples

23 files changed:
ext/spl/config.m4
ext/spl/examples/directoryfilterdots.inc [new file with mode: 0755]
ext/spl/examples/directorytree.inc [new file with mode: 0755]
ext/spl/examples/directorytree.php [new file with mode: 0755]
ext/spl/examples/filter.inc
ext/spl/examples/filteriterator.inc [new file with mode: 0755]
ext/spl/examples/findfile.php [new file with mode: 0755]
ext/spl/examples/limititerator.inc [new file with mode: 0755]
ext/spl/examples/recursiveiteratoriterator.inc [new file with mode: 0755]
ext/spl/examples/searchiterator.inc [new file with mode: 0755]
ext/spl/php_spl.c
ext/spl/php_spl.h
ext/spl/spl_array.c
ext/spl/spl_array.h
ext/spl/spl_directory.c
ext/spl/spl_directory.h [moved from ext/spl/spl_foreach.h with 86% similarity]
ext/spl/spl_engine.c
ext/spl/spl_engine.h
ext/spl/spl_foreach.c [deleted file]
ext/spl/spl_functions.c
ext/spl/spl_functions.h
ext/spl/spl_iterators.c [new file with mode: 0755]
ext/spl/spl_iterators.h [new file with mode: 0755]

index bce2b4f43aa9fa38a7d70de061ead56c6b577734..95bffc35c18636d70b04fb7e7163f287b6b48fc8 100755 (executable)
@@ -4,40 +4,7 @@ dnl config.m4 for extension SPL
 PHP_ARG_ENABLE(spl, enable SPL suppport,
 [  --disable-spl           Enable Standard PHP Library], yes)
 
-dnl first enable/disable all hooks
-
-PHP_ARG_ENABLE(spl-hook-all, enable all hooks,
-[  --enable-spl-hook-all       SPL: Enable all hooks])
-
-dnl now all single enable/disable for hooks
-
-PHP_ARG_ENABLE(spl-foreach, enable hook on foreach,
-[  --disable-spl-foreach       SPL: Disable hook on forach], yes)
-
-PHP_ARG_ENABLE(spl-array-read, enable hook on array read,
-[  --enable-spl-array-read     SPL: Enable hook on array read])
-
-PHP_ARG_ENABLE(spl-array-write, enable hook on array write,
-[  --enable-spl-array-write    SPL: Enable hook on array write (+read)])
-
-dnl last do checks on hooks
-
-if test "$PHP_SPL" != "no"; then
-  if test "$PHP_SPL_HOOK_ALL" != "no" -o "$PHP_SPL_FOREACH" != "no"; then
-    AC_DEFINE(SPL_FOREACH, 1, [Activate opcode hook on foreach])
-    PHP_SPL="yes"
-  fi
-  if test "$PHP_SPL_HOOK_ALL" != "no" -o "$PHP_SPL_ARRAY_READ" != "no" -o "$PHP_SPL_ARRAY_WRITE" != "no"; then
-    AC_DEFINE(SPL_ARRAY_READ, 1, [Activate opcode hook on array read])
-    PHP_SPL="yes"
-  fi
-  if test "$PHP_SPL_HOOK_ALL" != "no" -o "$PHP_SPL_ARRAY_WRITE" != "no"; then
-    AC_DEFINE(SPL_ARRAY_WRITE, 1, [Activate opcode hook on array write])
-    PHP_SPL="yes"
-  fi
-fi
-
 if test "$PHP_SPL" != "no"; then
     AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard Php Library) support]) 
-    PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_foreach.c spl_array.c spl_directory.c, $ext_shared)
+    PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c, $ext_shared)
 fi
diff --git a/ext/spl/examples/directoryfilterdots.inc b/ext/spl/examples/directoryfilterdots.inc
new file mode 100755 (executable)
index 0000000..3ca0e6a
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+class DirectoryFilterDots extends FilterIterator implements RecursiveIterator
+{
+       function __construct($path) {
+               parent::__construct(new DirectoryIterator($path));
+       }
+       
+       function accept() {
+               return !$this->it->isDot();
+       }
+       
+       function hasChildren() {
+               return $this->it->hasChildren();
+       }
+
+       function getChildren() {
+               return new DirectoryFilterDots($this->it->getPathname());
+       }
+       
+       function key() {
+               return $this->it->getPathname();
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/ext/spl/examples/directorytree.inc b/ext/spl/examples/directorytree.inc
new file mode 100755 (executable)
index 0000000..218ca51
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+
+class DirectoryTree extends RecursiveIteratorIterator
+{
+       function __construct($path) {
+               parent::__construct(new DirectoryFilterDots($path));
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/ext/spl/examples/directorytree.php b/ext/spl/examples/directorytree.php
new file mode 100755 (executable)
index 0000000..744a17a
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+
+/** tree view example
+ *
+ * Usage: php DirectoryTree.php <path>
+ *
+ * Simply specify the path to tree with parameter <path>.
+ *
+ * (c) Marcus Boerger
+ */
+
+$length = $argc > 3 ? $argv[3] : NULL;
+foreach(new LimitIterator(new DirectoryTree($argv[1]), @$argv[2], $length) as $pathname => $file) {
+       echo "$pathname\n";
+}
+
+?>
\ No newline at end of file
index 1cab580edd54240011de2d63cec3221f1f074216..d01dd62845c6228274e1197e01ab691675c38fc1 100755 (executable)
@@ -22,7 +22,7 @@ class filter implements spl_forward
         * method is called.
         *
         * @param it     Object that implements at least spl_forward
-        * @patam regex  Regular expression used as a filter.
+        * @param regex  Regular expression used as a filter.
         */
        function __construct(spl_forward $it, $regex) {
                if ($it instanceof spl_sequence) {
@@ -40,14 +40,18 @@ class filter implements spl_forward
                unset($this->it);
        }
 
-       protected function accept($curr) {
-               return ereg($this->regex, $curr);
+       /**
+        * Check whether a value can be accepted.
+        *
+        * @param value   used to test
+        * @return whether input is acceptable
+        */
+       protected function accept($value) {
+               return ereg($this->regex, $value);
        }
 
        /**
         * Fetch next element and store it.
-        *
-        * @return void
         */
        protected function fetch() {
                $this->curr = false;
@@ -63,8 +67,6 @@ class filter implements spl_forward
 
        /**
         * Move to next element
-        *
-        * @return void
         */
        function next() {
                $this->it->next();
diff --git a/ext/spl/examples/filteriterator.inc b/ext/spl/examples/filteriterator.inc
new file mode 100755 (executable)
index 0000000..43f8515
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @brief   Regular expression filter for string iterators
+ * @author  Marcus Boerger
+ * @version 1.0
+ *
+ * Instances of this class act as a filter around iterators whose elements
+ * are strings. In other words you can put an iterator into the constructor
+ * and the instance will only return elements which match the given regular 
+ * expression.
+ */
+abstract class FilterIterator implements Iterator
+{
+       protected $it;
+
+       /**
+        * Constructs a filter around an iterator whose elemnts are strings.
+        * If the given iterator is of type spl_sequence then its rewind()
+        * method is called.
+        *
+        * @param it     Object that implements at least spl_forward
+        * @patam regex  Regular expression used as a filter.
+        */
+       function __construct(Iterator $it) {
+               $this->it = $it;
+       }
+
+       function rewind() {     
+               $this->it->rewind();
+               $this->fetch();
+       }
+
+       abstract function accept();
+
+       /**
+        * Fetch next element and store it.
+        *
+        * @return void
+        */
+       protected function fetch() {
+               while ($this->it->hasMore()) {
+                       if ($this->accept()) {
+                               return;
+                       }
+                       $this->it->next();
+               };
+       }
+
+       /**
+        * Move to next element
+        *
+        * @return void
+        */
+       function next() {
+               $this->it->next();
+               $this->fetch();
+       }
+       
+       /**
+        * @return Whether more elements are available
+        */
+       function hasMore() {
+               return $this->it->hasMore();
+       }
+       
+       /**
+        * @return The current key
+        */
+       function key() {
+               return $this->it->key();
+       }
+       
+       /**
+        * @return The current value
+        */
+       function current() {
+               return $this->it->current();
+       }
+       
+       /**
+        * hidden __clone
+        */
+       protected function __clone() {
+               // disallow clone 
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/ext/spl/examples/findfile.php b/ext/spl/examples/findfile.php
new file mode 100755 (executable)
index 0000000..003111e
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+
+class FindFile extends SearchIterator
+{
+       protected $file;
+
+       function __construct($path, $file) {
+               $this->file = $file;
+               parent::__construct(new DirectoryTree($path));
+       }
+       function accept() {
+               return !strcmp($this->it->current(), $this->file);
+       }
+}
+
+foreach(new FindFile($argv[1], $argv[2]) as $pathname => $file) echo "$pathname\n";
+?>
\ No newline at end of file
diff --git a/ext/spl/examples/limititerator.inc b/ext/spl/examples/limititerator.inc
new file mode 100755 (executable)
index 0000000..c1a19fe
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+class LimitIterator implements Iterator
+{
+       protected $it;
+       protected $offset;
+       protected $count;
+       protected $index;
+
+       // negative offset is  respected
+       // count === NULL means all
+       function __construct(Iterator $it, $offset = 0, $count = NULL)
+       {
+               $this->it     = $it;
+               $this->offset = $offset;
+               $this->count  = $count;
+               $this->index  = 0;
+       }
+       
+       function rewind()
+       {
+               $this->it->rewind();
+               $this->index = 0;
+               while($this->index < $this->offset && $this->it->hasMore()) {
+                       $this->next();
+               }
+       }
+       
+       function hasMore() {
+               return (is_null($this->count) || $this->index < $this->offset + $this->count)
+                        && $this->it->hasMore();
+       }
+       
+       function key() {
+               return $this->it->key();
+       }
+
+       function current() {
+               return $this->it->current();
+       }
+
+       function next() {
+               $this->it->next();
+               $this->index++;
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/ext/spl/examples/recursiveiteratoriterator.inc b/ext/spl/examples/recursiveiteratoriterator.inc
new file mode 100755 (executable)
index 0000000..95d52d7
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ * @brief   Iterates through recursive iterators
+ * @author  Marcus Boerger
+ * @version 1.0
+ *
+ */
+class RecursiveIteratorIterator implements Iterator
+{
+       protected $ait = array();
+       protected $count = 0;
+
+       function __construct(RecursiveIterator $it) {
+               $this->count = 1;
+               $this->ait[0] = $it;
+       }
+
+
+       function rewind() {
+               while ($this->count > 1) {
+                       unset($this->ait[--$this->count]);
+               }
+               $this->ait[0]->rewind();
+               $this->ait[0]->recursed = false;
+       }
+       
+       function hasMore() {
+               $count = $this->count;
+               while ($count--) {
+                       $it = $this->ait[$count];
+                       if ($it->hasMore()) {// || (!$it->recursed && $it->isRecursive())) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
+       function key() {
+               $it = $this->ait[$this->count-1];
+               return $it->key();
+       }
+       
+       function current() {
+               $it = $this->ait[$this->count-1];
+               return $it->current();
+       }
+       
+       function next() {
+               while ($this->count) {
+                       $it = $this->ait[$this->count-1];
+                       if ($it->hasMore()) {
+                               if (!$it->recursed && $it->hasChildren()) {
+                                       $it->recursed = true;
+                                       $sub = $it->getChildren();
+                                       $sub->recursed = false;
+                                       $sub->rewind();
+                                       if ($sub->hasMore()) {
+                                               $this->ait[$this->count++] = $sub;
+                                               if (!is_a($sub, 'RecursiveIterator')) {
+                                                       throw new Exception(get_class($sub).'::getChildren() must return an object that implements RecursiveIterator');
+                                               } 
+                                               return;
+                                       }
+                                       unset($sub);
+                               }
+                               $it->next();
+                               $it->recursed = false;
+                               if ($it->hasMore()) {
+                                       return;
+                               }
+                               $it->recursed = false;
+                       }
+                       if ($this->count <= 1) {
+                               return;
+                       }
+                       unset($this->ait[--$this->count]);
+                       $it = $this->ait[$this->count-1];
+               }
+       }
+       
+       function getCurrentIterator() {
+               return $this->ait[$this->count-1];
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/ext/spl/examples/searchiterator.inc b/ext/spl/examples/searchiterator.inc
new file mode 100755 (executable)
index 0000000..42c249b
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+abstract class SearchIterator extends FilterIterator
+{
+       private $done = false;
+
+       function hasMore() {
+               return !$this->done && parent::hasMore();
+       }
+       
+       function next() {
+               $this->done = true;
+       }
+}
+
+?>
\ No newline at end of file
index 7617f3fa9e878b6c708e3cf4da2abcb9c0c4fa9f..c5941d7c07545ddcf88fbf22f5c317041d3b74e6 100755 (executable)
@@ -26,8 +26,9 @@
 #include "php_spl.h"
 #include "spl_functions.h"
 #include "spl_engine.h"
-#include "spl_foreach.h"
 #include "spl_array.h"
+#include "spl_directory.h"
+#include "spl_iterators.h"
 
 #ifdef COMPILE_DL_SPL
 ZEND_GET_MODULE(spl)
@@ -61,12 +62,8 @@ zend_module_entry spl_module_entry = {
 };
 /* }}} */
 
-zend_class_entry *spl_ce_iterator;
-zend_class_entry *spl_ce_forward;
-zend_class_entry *spl_ce_assoc;
-zend_class_entry *spl_ce_sequence;
-zend_class_entry *spl_ce_forward_assoc;
-zend_class_entry *spl_ce_sequence_assoc;
+zend_class_entry *spl_ce_recursive_it;
+zend_class_entry *spl_ce_recursive_it_it;
 zend_class_entry *spl_ce_array_read;
 zend_class_entry *spl_ce_array_access;
 
@@ -81,106 +78,16 @@ function_entry spl_functions_none[] = {
  */
 static void spl_init_globals(zend_spl_globals *spl_globals)
 {
-#ifdef SPL_FOREACH
-       ZEND_EXECUTE_HOOK(ZEND_FE_RESET);
-       ZEND_EXECUTE_HOOK(ZEND_FE_FETCH);
-       ZEND_EXECUTE_HOOK(ZEND_SWITCH_FREE);
-#endif
-
-#if defined(SPL_ARRAY_READ) | defined(SPL_ARRAY_WRITE)
-       ZEND_EXECUTE_HOOK(ZEND_FETCH_DIM_R);
-       ZEND_EXECUTE_HOOK(ZEND_FETCH_DIM_W);
-       ZEND_EXECUTE_HOOK(ZEND_FETCH_DIM_RW);
-#endif
-
-#ifdef SPL_ARRAY_WRITE
-       ZEND_EXECUTE_HOOK(ZEND_ASSIGN_DIM);
-       ZEND_EXECUTE_HOOK(ZEND_UNSET_DIM_OBJ);
-#endif /* SPL_ARRAY_WRITE */
 }
 /* }}} */
 
-PHP_FUNCTION(spl_abstract) {}
-
-#define SPL_ABSTRACT_FE(class, name, arg_info) \
-       { #name, ZEND_FN(spl_abstract), arg_info, sizeof(arg_info)/sizeof(struct _zend_arg_info)-1, ZEND_ACC_ABSTRACT|ZEND_ACC_PUBLIC },
-
-static
-ZEND_BEGIN_ARG_INFO(arginfo_one_param, 0)
-       ZEND_ARG_INFO(0, index)
-ZEND_END_ARG_INFO();
-
-static
-ZEND_BEGIN_ARG_INFO(arginfo_two_params, 0)
-       ZEND_ARG_INFO(0, index)
-       ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO();
-
-function_entry spl_funcs_iterator[] = {
-       SPL_ABSTRACT_FE(iterator, newIterator, NULL)
-       {NULL, NULL, NULL}
-};
-
-function_entry spl_funcs_forward[] = {
-       SPL_ABSTRACT_FE(forward, current,  NULL)
-       SPL_ABSTRACT_FE(forward, next,     NULL)
-       SPL_ABSTRACT_FE(forward, hasMore,  NULL)
-       {NULL, NULL, NULL}
-};
-
-function_entry spl_funcs_sequence[] = {
-       SPL_ABSTRACT_FE(sequence, rewind,  NULL)
-       {NULL, NULL, NULL}
-};
-
-function_entry spl_funcs_assoc[] = {
-       SPL_ABSTRACT_FE(assoc, key,  NULL)
-       {NULL, NULL, NULL}
-};
-
-function_entry *spl_funcs_forward_assoc  = NULL;
-function_entry *spl_funcs_sequence_assoc = NULL;
-
-function_entry spl_funcs_array_read[] = {
-       SPL_ABSTRACT_FE(array_read, get,     arginfo_one_param)
-       SPL_ABSTRACT_FE(array_read, exists,  arginfo_one_param)
-       {NULL, NULL, NULL}
-};
-
-function_entry spl_funcs_array_access[] = {
-       SPL_ABSTRACT_FE(array_access, set,  arginfo_two_params)
-       SPL_ABSTRACT_FE(array_access, del,  arginfo_one_param)
-       {NULL, NULL, NULL}
-};
-
 /* {{{ PHP_MINIT_FUNCTION(spl)
  */
 PHP_MINIT_FUNCTION(spl)
 {
        ZEND_INIT_MODULE_GLOBALS(spl, spl_init_globals, NULL);
 
-       REGISTER_SPL_INTERFACE(iterator);
-
-       REGISTER_SPL_INTERFACE(forward);
-
-       REGISTER_SPL_INTERFACE(sequence);
-       REGISTER_SPL_IMPLEMENT(sequence, forward);
-
-       REGISTER_SPL_INTERFACE(assoc);
-
-       REGISTER_SPL_INTERFACE(forward_assoc);
-       REGISTER_SPL_IMPLEMENT(forward_assoc, assoc);
-       REGISTER_SPL_IMPLEMENT(forward_assoc, forward);
-
-       REGISTER_SPL_INTERFACE(sequence_assoc);
-       REGISTER_SPL_IMPLEMENT(sequence_assoc, forward_assoc);
-       REGISTER_SPL_IMPLEMENT(sequence_assoc, sequence);
-
-       REGISTER_SPL_INTERFACE(array_read);
-
-       REGISTER_SPL_INTERFACE(array_access);
-       REGISTER_SPL_IMPLEMENT(array_access, array_read);
-
+       PHP_MINIT(spl_iterators)(INIT_FUNC_ARGS_PASSTHRU);
        PHP_MINIT(spl_array)(INIT_FUNC_ARGS_PASSTHRU);
        PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU);
 
@@ -256,10 +163,8 @@ PHP_MINFO_FUNCTION(spl)
        php_info_print_table_row(2,    "forward",            foreach);
        php_info_print_table_row(2,    "sequence",           foreach);
        php_info_print_table_row(2,    "assoc",              foreach);
-       php_info_print_table_row(2,    "forward_assoc",      foreach);
-       php_info_print_table_row(2,    "sequence_assoc",     foreach);
-       php_info_print_table_row(2,    "array_read",         array_read);
-       php_info_print_table_row(2,    "array_access",       array_write);
+       php_info_print_table_row(2,    "ArrayRead",         array_read);
+       php_info_print_table_row(2,    "ArrayAccess",       array_write);
        php_info_print_table_end();
 }
 /* }}} */
@@ -305,14 +210,13 @@ PHP_FUNCTION(spl_classes)
 {
        array_init(return_value);
 
-       SPL_ADD_CLASS(iterator);
-       SPL_ADD_CLASS(forward);
-       SPL_ADD_CLASS(sequence);
-       SPL_ADD_CLASS(assoc);
-       SPL_ADD_CLASS(forward_assoc);
-       SPL_ADD_CLASS(sequence_assoc);
-       SPL_ADD_CLASS(array_read);
-       SPL_ADD_CLASS(array_access);
+       SPL_ADD_CLASS(ArrayAccess);
+       SPL_ADD_CLASS(ArrayClass);
+       SPL_ADD_CLASS(ArrayIterator);
+       SPL_ADD_CLASS(ArrayRead);
+       SPL_ADD_CLASS(DirectoryIterator);
+       SPL_ADD_CLASS(RecursiveIterator);
+       SPL_ADD_CLASS(RecursiveIteratorIterator);
 }
 /* }}} */
 
index b8de833022b036d6a5798cced0f21ff7c547e883..474da85c010940d03db2ae7cd2dfe9eb1a20df2e 100755 (executable)
@@ -83,22 +83,10 @@ extern int spl_globals_id;
 extern zend_spl_globals spl_globals;
 #endif
 
-extern zend_class_entry *spl_ce_iterator;
-extern zend_class_entry *spl_ce_forward;
-extern zend_class_entry *spl_ce_sequence;
-extern zend_class_entry *spl_ce_assoc;
-extern zend_class_entry *spl_ce_forward_assoc;
-extern zend_class_entry *spl_ce_sequence_assoc;
-extern zend_class_entry *spl_ce_array_read;
-extern zend_class_entry *spl_ce_array_access;
-
 PHP_FUNCTION(spl_classes);
 PHP_FUNCTION(class_parents);
 PHP_FUNCTION(class_implements);
 
-PHP_MINIT_FUNCTION(spl_array);
-PHP_MINIT_FUNCTION(spl_directory);
-
 #endif /* PHP_SPL_H */
 
 /*
index 95132cb6c27f0817627d8ce563bc8def6a795554..6df776ac6cf4dd0f7943ff49633539de61b4037f 100755 (executable)
 #include "php.h"
 #include "php_ini.h"
 #include "ext/standard/info.h"
-#include "zend_compile.h"
+#include "zend_interfaces.h"
 
 #include "php_spl.h"
 #include "spl_functions.h"
 #include "spl_engine.h"
 #include "spl_array.h"
 
-#define DELETE_ZVAL(z) \
-       if ((z)->refcount < 2) { \
-               zval_dtor(z); \
-               FREE_ZVAL(z); /* maybe safe_free_zval_ptr is needed for the uninitialised things */ \
-       }
-
-#define DELETE_RET_ZVAL(z) \
-       if ((z)->refcount < 3) { \
-               zval_dtor(z); \
-               FREE_ZVAL(z); /* maybe safe_free_zval_ptr is needed for the uninitialised things */ \
-       }
-
-#define AI_PTR_2_PTR_PTR(ai) \
-       (ai).ptr_ptr = &((ai).ptr)
-
-/* {{{ spl_fetch_dimension_address */
-int spl_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
-{
-       zval **obj;
-       zend_class_entry *obj_ce;
-       spl_is_a is_a;
-
-       obj = spl_get_zval_ptr_ptr(op1, Ts TSRMLS_CC);
-
-       if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) {
-               return 1;
-       }
-
-       is_a = spl_implements(obj_ce);
-
-       if (is_a & SPL_IS_A_ARRAY_READ) {
-               zval **retval = &(T(result->u.var).var.ptr);
-               zval *dim = spl_get_zval_ptr(op2, Ts, &EG(free_op2) TSRMLS_CC);
-               zval *exists;
-
-               spl_call_method_1(obj, obj_ce, NULL, "exists", sizeof("exists")-1, &exists, dim);
-               if (!i_zend_is_true(exists)) {
-                       if (type == BP_VAR_R || type == BP_VAR_RW) {
-                               SEPARATE_ZVAL(&dim);
-                               convert_to_string_ex(&dim);
-                               zend_error(E_NOTICE, "Undefined index:  %s", Z_STRVAL_P(dim));
-                               DELETE_ZVAL(dim);
-                       }
-                       if (type == BP_VAR_R || type == BP_VAR_IS) {
-                               DELETE_RET_ZVAL(exists);
-                               *retval = &EG(error_zval);
-                               (*retval)->refcount++;
-                               FREE_OP(Ts, op2, EG(free_op2));
-                               SELECTIVE_PZVAL_LOCK(*retval, result);
-                               return 0;
-                       }
-               }
-               DELETE_RET_ZVAL(exists);
-               if (type == BP_VAR_R || type == BP_VAR_IS) {
-                       spl_call_method_1(obj, obj_ce, NULL, "get", sizeof("get")-1, retval, dim);
-               }
-               FREE_OP(Ts, op2, EG(free_op2));
-               return 0;
-       }
-       return 1;
-}
-/* }}} */
-
-/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_R) */
-#ifdef SPL_ARRAY_READ
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_R)
-{
-       if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_R TSRMLS_CC))
-       {
-               if (EX(opline)->extended_value == ZEND_FETCH_ADD_LOCK) {
-                       spl_pzval_lock_func(*EX_T(EX(opline)->op1.u.var).var.ptr_ptr);
-               }
-               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-
-               AI_PTR_2_PTR_PTR(EX_T(EX(opline)->result.u.var).var);
-               NEXT_OPCODE();
-       }
-       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_R);
-}
-#endif
-/* }}} */
-
-/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_W) */
-#ifdef SPL_ARRAY_READ
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_W)
-{
-       if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_W TSRMLS_CC))
-       {
-               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
 
-               NEXT_OPCODE();
-       }
-       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_W);
-}
-#endif
-/* }}} */
-
-/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW) */
-#ifdef SPL_ARRAY_READ
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW)
-{
-       if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_RW TSRMLS_CC))
-       {
-               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-
-               NEXT_OPCODE();
-       }
-       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_RW);
-}
-#endif
-/* }}} */
-
-static inline zval **spl_get_obj_zval_ptr_ptr(znode *op, temp_variable *Ts, int type TSRMLS_DC)
-{
-       if (op->op_type == IS_UNUSED) {
-               if (EG(This)) {
-                       /* this should actually never be modified, _ptr_ptr is modified only when
-                          the object is empty */
-                       return &EG(This);
-               } else {
-                       zend_error(E_ERROR, "Using $this when not in object context");
-               }
-       }
-       return spl_get_zval_ptr_ptr(op, Ts TSRMLS_CC);
-}
-
-/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM) */
-#ifdef SPL_ARRAY_WRITE
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM)
-{
-       zval **obj;
-       zend_class_entry *obj_ce;
-       spl_is_a is_a;
-
-       obj = spl_get_obj_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), 0 TSRMLS_CC);
-
-       if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) {
-               ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN_DIM);
-       }
-
-       is_a = spl_implements(obj_ce);
-
-       if (is_a & SPL_IS_A_ARRAY_ACCESS) {
-               znode *op2 = &EX(opline)->op2;
-               zval *index = spl_get_zval_ptr(op2, EX(Ts), &EG(free_op2), BP_VAR_R);
-               zval *free_value;
-               zend_op *value_op = EX(opline)+1;
-               zval *value = spl_get_zval_ptr(&value_op->op1, EX(Ts), &free_value, BP_VAR_R);
-               zval tmp;
-               zval *retval;
-
-               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-
-               /* here we are sure we are dealing with an object */
-               switch (op2->op_type) {
-                       case IS_CONST:
-                               /* already a constant string */
-                               break;
-                       case IS_VAR:
-                               tmp = *index;
-                               zval_copy_ctor(&tmp);
-                               convert_to_string(&tmp);
-                               index = &tmp;
-                               break;
-                       case IS_TMP_VAR:
-                               convert_to_string(index);
-                               break;
-               }
-
-               /* separate our value if necessary */
-               if (value_op->op1.op_type == IS_TMP_VAR) {
-                       zval *orig_value = value;
-       
-                       ALLOC_ZVAL(value);
-                       *value = *orig_value;
-                       value->is_ref = 0;
-                       value->refcount = 0;
-               }
-
-               spl_call_method_2(obj, obj_ce, NULL, "set", sizeof("set")-1, &retval, index, value);
-
-               if (index == &tmp) {
-                       zval_dtor(index);
-               }
-
-               FREE_OP(Ts, op2, EG(free_op2));
-               if (&EX(opline)->result) {
-                       if (retval->refcount < 2) {
-                               zend_error(E_WARNING, "Method %s::set() did not return a value, using input value", obj_ce->name);
-                               EX_T(EX(opline)->result.u.var).var.ptr = value;
-                               SELECTIVE_PZVAL_LOCK(value, &EX(opline)->result);
-                               DELETE_RET_ZVAL(retval);                        
-                       } else {
-                               SELECTIVE_PZVAL_LOCK(retval, &EX(opline)->result);
-                               EX_T(EX(opline)->result.u.var).var.ptr = retval;
-                               retval->refcount--;
-                       }
-                       EX_T(EX(opline)->result.u.var).var.ptr_ptr = NULL;
-               } else {
-                       DELETE_RET_ZVAL(retval);                        
-               }
-
-               EX(opline)++;
-               NEXT_OPCODE();
-       }
-       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN_DIM);
-}
-#endif
-/* }}} */
-
-/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_UNSET_DIM_OBJ) */
-#ifdef SPL_ARRAY_WRITE
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_UNSET_DIM_OBJ)
-{
-       zval **obj;
-       zend_class_entry *obj_ce;
-       spl_is_a is_a;
-
-       if (EX(opline)->extended_value != ZEND_UNSET_DIM) {
-               ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ);
-       }
-
-       obj = spl_get_obj_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), 0 TSRMLS_CC);
-
-       if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) {
-               ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ);
-       }
-
-       is_a = spl_implements(obj_ce);
-
-       if (is_a & SPL_IS_A_ARRAY_ACCESS) {
-               znode *op2 = &EX(opline)->op2;
-               zval *index = spl_get_zval_ptr(op2, EX(Ts), &EG(free_op2), BP_VAR_R);
-               zval tmp;
-               zval *retval;
-
-               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-
-               /* here we are sure we are dealing with an object */
-               switch (op2->op_type) {
-                       case IS_CONST:
-                               /* already a constant string */
-                               break;
-                       case IS_VAR:
-                               tmp = *index;
-                               zval_copy_ctor(&tmp);
-                               convert_to_string(&tmp);
-                               index = &tmp;
-                               break;
-                       case IS_TMP_VAR:
-                               convert_to_string(index);
-                               break;
-               }
-
-               spl_call_method_1(obj, obj_ce, NULL, "del", sizeof("del")-1, &retval, index);
+static
+ZEND_BEGIN_ARG_INFO(arginfo_one_param, 0)
+       ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO();
 
-               if (index == &tmp) {
-                       zval_dtor(index);
-               }
+static
+ZEND_BEGIN_ARG_INFO(arginfo_two_params, 0)
+       ZEND_ARG_INFO(0, index)
+       ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO();
 
-               FREE_OP(Ts, op2, EG(free_op2));
-               DELETE_RET_ZVAL(retval);                        
+function_entry spl_funcs_ArrayRead[] = {
+       SPL_ABSTRACT_ME(ArrayRead, get,     arginfo_one_param)
+       SPL_ABSTRACT_ME(ArrayRead, exists,  arginfo_one_param)
+       {NULL, NULL, NULL}
+};
 
-               NEXT_OPCODE();
-       }
-       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ);
-}
-#endif
-/* }}} */
+function_entry spl_funcs_ArrayAccess[] = {
+       SPL_ABSTRACT_ME(ArrayAccess, set,  arginfo_two_params)
+       SPL_ABSTRACT_ME(ArrayAccess, del,  arginfo_one_param)
+       {NULL, NULL, NULL}
+};
 
-SPL_CLASS_FUNCTION(array, __construct);
-SPL_CLASS_FUNCTION(array, newIterator);
-SPL_CLASS_FUNCTION(array, rewind);
-SPL_CLASS_FUNCTION(array, current);
-SPL_CLASS_FUNCTION(array, key);
-SPL_CLASS_FUNCTION(array, next);
-SPL_CLASS_FUNCTION(array, hasMore);
+SPL_METHOD(Array, __construct);
+SPL_METHOD(Array, getIterator);
+SPL_METHOD(Array, rewind);
+SPL_METHOD(Array, current);
+SPL_METHOD(Array, key);
+SPL_METHOD(Array, next);
+SPL_METHOD(Array, hasMore);
 
 static
 ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
        ZEND_ARG_INFO(0, array)
 ZEND_END_ARG_INFO();
 
-static zend_function_entry spl_array_class_functions[] = {
-       SPL_CLASS_FE(array, __construct,   arginfo_array___construct, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(array, newIterator,   NULL, ZEND_ACC_PUBLIC)
+static zend_function_entry spl_funcs_ArrayClass[] = {
+       SPL_ME(Array, __construct,   arginfo_array___construct, ZEND_ACC_PUBLIC)
+       SPL_ME(Array, getIterator,   NULL, ZEND_ACC_PUBLIC)
        {NULL, NULL, NULL}
 };
 
-static zend_function_entry spl_array_it_class_functions[] = {
-       SPL_CLASS_FE(array, __construct,   arginfo_array___construct, ZEND_ACC_PRIVATE)
-       SPL_CLASS_FE(array, rewind,        NULL, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(array, current,       NULL, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(array, key,           NULL, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(array, next,          NULL, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(array, hasMore,       NULL, ZEND_ACC_PUBLIC)
+static zend_function_entry spl_funcs_ArrayIterator[] = {
+       SPL_ME(Array, __construct,   arginfo_array___construct, ZEND_ACC_PRIVATE)
+       SPL_ME(Array, rewind,        NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(Array, current,       NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(Array, key,           NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(Array, next,          NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(Array, hasMore,       NULL, ZEND_ACC_PUBLIC)
        {NULL, NULL, NULL}
 };
 
-static zend_object_handlers spl_array_handlers;
-static zend_class_entry *   spl_ce_array;
+zend_class_entry *   spl_ce_ArrayRead;
+zend_class_entry *   spl_ce_ArrayAccess;
 
-static zend_object_handlers spl_array_it_handlers;
-static zend_class_entry *   spl_ce_array_it;
+zend_object_handlers spl_handler_ArrayClass;
+zend_class_entry *   spl_ce_ArrayClass;
+
+zend_object_handlers spl_handler_ArrayIterator;
+zend_class_entry *   spl_ce_ArrayIterator;
 
 typedef struct _spl_array_object {
        zend_object       std;
@@ -384,10 +141,10 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s
        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);
-       if (class_type == spl_ce_array_it) {
-               retval.handlers = &spl_array_it_handlers;
+       if (class_type == spl_ce_ArrayIterator) {
+               retval.handlers = &spl_handler_ArrayIterator;
        } else {
-               retval.handlers = &spl_array_handlers;
+               retval.handlers = &spl_handler_ArrayClass;
        }
        return retval;
 }
@@ -420,20 +177,6 @@ static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
 }
 /* }}} */
 
-/* {{{ spl_array_get_ce */
-static zend_class_entry *spl_array_get_ce(zval *object TSRMLS_DC)
-{
-       return spl_ce_array;
-}
-/* }}} */
-
-/* {{{ spl_array_it_get_ce */
-static zend_class_entry *spl_array_it_get_ce(zval *object TSRMLS_DC)
-{
-       return spl_ce_array_it;
-}
-/* }}} */
-
 /* {{{ spl_array_read_dimension */
 static zval *spl_array_read_dimension(zval *object, zval *offset TSRMLS_DC)
 {
@@ -544,20 +287,23 @@ static HashTable *spl_array_get_properties(zval *object TSRMLS_DC)
 /* {{{ PHP_MINIT_FUNCTION(spl_array) */
 PHP_MINIT_FUNCTION(spl_array)
 {
-       REGISTER_SPL_STD_CLASS_EX(array, spl_array_object_new, spl_array_class_functions);
-       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.read_dimension = spl_array_read_dimension;
-       spl_array_handlers.write_dimension = spl_array_write_dimension;
-       spl_array_handlers.unset_dimension = spl_array_unset_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;
+       REGISTER_SPL_INTERFACE(ArrayRead);
+
+       REGISTER_SPL_INTERFACE(ArrayAccess);
+       zend_class_implements(spl_ce_ArrayAccess TSRMLS_CC, 1, spl_ce_ArrayRead);
+
+       REGISTER_SPL_STD_CLASS_EX(ArrayClass, spl_array_object_new, spl_funcs_ArrayClass);
+       zend_class_implements(spl_ce_ArrayClass TSRMLS_CC, 1, zend_ce_aggregate);
+       memcpy(&spl_handler_ArrayClass, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+       spl_handler_ArrayClass.clone_obj = spl_array_object_clone;
+       spl_handler_ArrayClass.read_dimension = spl_array_read_dimension;
+       spl_handler_ArrayClass.write_dimension = spl_array_write_dimension;
+       spl_handler_ArrayClass.unset_dimension = spl_array_unset_dimension;
+       spl_handler_ArrayClass.get_properties = spl_array_get_properties;
+
+       REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
+       zend_class_implements(spl_ce_ArrayIterator TSRMLS_CC, 1, zend_ce_iterator);
+       memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayClass, sizeof(zend_object_handlers));
 
        return SUCCESS;
 }
@@ -566,7 +312,7 @@ PHP_MINIT_FUNCTION(spl_array)
 /* {{{ proto void spl_array::__construct(array|object ar = array())
        proto void spl_array_it::__construct(array|object ar = array())
  Cronstructs a new array iterator from a path. */
-SPL_CLASS_FUNCTION(array, __construct)
+SPL_METHOD(Array, __construct)
 {
        zval *object = getThis();
        spl_array_object *intern;
@@ -598,9 +344,9 @@ SPL_CLASS_FUNCTION(array, __construct)
 }
 /* }}} */
 
-/* {{{ proto spl_array_it|NULL spl_array::newIterator()
-   Create a new iterator from a spl_array instance */
-SPL_CLASS_FUNCTION(array, newIterator)
+/* {{{ proto spl_array_it|NULL ArrayClass::getIterator()
+   Create a new iterator from a ArrayClass instance */
+SPL_METHOD(Array, getIterator)
 {
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
@@ -613,7 +359,7 @@ SPL_CLASS_FUNCTION(array, newIterator)
        }
 
        return_value->type = IS_OBJECT;
-       return_value->value.obj = spl_array_object_new_ex(spl_ce_array_it, &iterator, intern TSRMLS_CC);
+       return_value->value.obj = spl_array_object_new_ex(spl_ce_ArrayIterator, &iterator, intern TSRMLS_CC);
        return_value->refcount = 1;
        return_value->is_ref = 1;
 }
@@ -643,7 +389,7 @@ ZEND_API int spl_hash_pos_exists(spl_array_object * intern TSRMLS_DC)
 
 /* {{{ proto void spl_array_it::rewind()
    Rewind array back to the start */
-SPL_CLASS_FUNCTION(array, rewind)
+SPL_METHOD(Array, rewind)
 {
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
@@ -660,7 +406,7 @@ SPL_CLASS_FUNCTION(array, rewind)
 
 /* {{{ proto mixed|false spl_array_it::current()
    Return current array entry */
-SPL_CLASS_FUNCTION(array, current)
+SPL_METHOD(Array, current)
 {
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
@@ -687,7 +433,7 @@ SPL_CLASS_FUNCTION(array, current)
 
 /* {{{ proto mixed|false spl_array_it::key()
    Return current array key */
-SPL_CLASS_FUNCTION(array, key)
+SPL_METHOD(Array, key)
 {
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
@@ -721,7 +467,7 @@ SPL_CLASS_FUNCTION(array, key)
 
 /* {{{ proto void spl_array_it::next()
    Move to next entry */
-SPL_CLASS_FUNCTION(array, next)
+SPL_METHOD(Array, next)
 {
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
@@ -742,7 +488,7 @@ SPL_CLASS_FUNCTION(array, next)
 
 /* {{{ proto bool spl_array_it::hasMore()
    Check whether array contains more entries */
-SPL_CLASS_FUNCTION(array, hasMore)
+SPL_METHOD(Array, hasMore)
 {
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
index 840a9627eb21d0ccd39e643081563d9be296cb8c..d4bc03d87657617883cc7f1b63f00df5cacd69d3 100755 (executable)
 #include "php.h"
 #include "php_spl.h"
 
-#ifdef SPL_ARRAY_READ
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_R);
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_W);
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW);
-#endif
+extern zend_class_entry *spl_ce_ArrayRead;
+extern zend_class_entry *spl_ce_ArrayAccess;
+extern zend_class_entry *spl_ce_ArrayClass;
+extern zend_class_entry *spl_ce_ArrayIterator;
 
-#ifdef SPL_ARRAY_WRITE
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM);
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_UNSET_DIM_OBJ);
-#endif
+PHP_MINIT_FUNCTION(spl_array);
 
 #endif /* SPL_ARRAY_H */
 
index 045e5d4368130d1ebac8165db46ca4ce442e0873..444ac267049bd6644f9d9b008d27c73f389d3a3e 100755 (executable)
 #include "ext/standard/info.h"
 #include "zend_compile.h"
 #include "zend_default_classes.h"
+#include "zend_interfaces.h"
 
 #include "php_spl.h"
 #include "spl_functions.h"
 #include "spl_engine.h"
-#include "spl_foreach.h"
+#include "spl_iterators.h"
 
 #include "php.h"
 #include "fopen_wrappers.h"
 
-SPL_CLASS_FUNCTION(dir, __construct);
-SPL_CLASS_FUNCTION(dir, rewind);
-SPL_CLASS_FUNCTION(dir, current);
-SPL_CLASS_FUNCTION(dir, next);
-SPL_CLASS_FUNCTION(dir, hasMore);
-SPL_CLASS_FUNCTION(dir, getPath);
-
+#include "ext/standard/basic_functions.h"
+#include "ext/standard/php_filestat.h"
+
+/* forward declaration for all methods use (class-name, method-name) */
+SPL_METHOD(DirectoryIterator, __construct);
+SPL_METHOD(DirectoryIterator, rewind);
+SPL_METHOD(DirectoryIterator, hasMore);
+SPL_METHOD(DirectoryIterator, key);
+SPL_METHOD(DirectoryIterator, current);
+SPL_METHOD(DirectoryIterator, next);
+SPL_METHOD(DirectoryIterator, getPath);
+SPL_METHOD(DirectoryIterator, getFilename);
+SPL_METHOD(DirectoryIterator, getPathname);
+SPL_METHOD(DirectoryIterator, isDot);
+SPL_METHOD(DirectoryIterator, isDir);
+
+SPL_METHOD(DirectoryTreeIterator, key);
+SPL_METHOD(DirectoryTreeIterator, hasChildren);
+SPL_METHOD(DirectoryTreeIterator, getChildren);
+
+
+/* declare method parameters */
+/* supply a name and default to call by parameter */
 static
-ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0)
-       ZEND_ARG_INFO(0, path)
+ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0) 
+       ZEND_ARG_INFO(0, path)  /* parameter name */
 ZEND_END_ARG_INFO();
 
-static zend_function_entry spl_dir_class_functions[] = {
-       SPL_CLASS_FE(dir, __construct,   arginfo_dir___construct, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(dir, rewind,        NULL, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(dir, current,       NULL, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(dir, next,          NULL, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(dir, hasMore,       NULL, ZEND_ACC_PUBLIC)
-       SPL_CLASS_FE(dir, getPath,       NULL, ZEND_ACC_PUBLIC)
+
+/* the method table */
+/* each method can have its own parameters and visibility */
+static zend_function_entry spl_ce_dir_class_functions[] = {
+       SPL_ME(DirectoryIterator, __construct,   arginfo_dir___construct, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, rewind,        NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, hasMore,       NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, key,           NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, current,       NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, next,          NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, getPath,       NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, getFilename,   NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, getPathname,   NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, isDot,         NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryIterator, isDir,         NULL, ZEND_ACC_PUBLIC)
+       {NULL, NULL, NULL}
+};
+
+static zend_function_entry spl_ce_dir_tree_class_functions[] = {
+       SPL_ME(DirectoryTreeIterator, key,           NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryTreeIterator, hasChildren,   NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(DirectoryTreeIterator, getChildren,   NULL, ZEND_ACC_PUBLIC)
        {NULL, NULL, NULL}
 };
 
-static zend_object_handlers spl_dir_handlers;
-static zend_class_entry *spl_ce_dir;
 
-typedef struct _spl_dir_object {
+/* declare the class handlers */
+static zend_object_handlers spl_ce_dir_handlers;
+
+
+/* decalre the class entry */
+zend_class_entry *spl_ce_DirectoryIterator;
+zend_class_entry *spl_ce_DirectoryTreeIterator;
+
+
+/* the overloaded class structure */
+
+/* overloading the structure results in the need of having 
+   dedicated creatin/cloning/destruction functions */
+typedef struct _spl_ce_dir_object {
        zend_object       std;
        php_stream        *dirp;
        php_stream_dirent entry;
        char              *path;
-} spl_dir_object;
+       int               index;
+} spl_ce_dir_object;
+
 
-/* {{{ spl_dir_object_dtor */
-static void spl_dir_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
+/* {{{ spl_ce_dir_object_dtor */
+/* close all resources and the memory allocated for the object */
+static void spl_ce_dir_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
 {
-       spl_dir_object *intern = (spl_dir_object *)object;
+       spl_ce_dir_object *intern = (spl_ce_dir_object *)object;
 
        zend_hash_destroy(intern->std.properties);
        FREE_HASHTABLE(intern->std.properties);
@@ -86,15 +132,26 @@ static void spl_dir_object_dtor(void *object, zend_object_handle handle TSRMLS_D
 }
 /* }}} */
 
-/* {{{ spl_dir_object_new */
-static zend_object_value spl_dir_object_new_ex(zend_class_entry *class_type, spl_dir_object **obj TSRMLS_DC)
+
+/* {{{ spl_ce_dir_object_new */
+/* creates the object by 
+   - allocating memory 
+   - initializing the object members
+   - storing the object
+   - setting it's handlers
+
+   called from 
+   - clone
+   - new
+ */
+static zend_object_value spl_ce_dir_object_new_ex(zend_class_entry *class_type, spl_ce_dir_object **obj TSRMLS_DC)
 {
        zend_object_value retval;
-       spl_dir_object *intern;
+       spl_ce_dir_object *intern;
        zval *tmp;
 
-       intern = emalloc(sizeof(spl_dir_object));
-       memset(intern, 0, sizeof(spl_dir_object));
+       intern = emalloc(sizeof(spl_ce_dir_object));
+       memset(intern, 0, sizeof(spl_ce_dir_object));
        intern->std.ce = class_type;
        *obj = intern;
 
@@ -102,27 +159,31 @@ static zend_object_value spl_dir_object_new_ex(zend_class_entry *class_type, spl
        zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
 
-       retval.handle = zend_objects_store_put(intern, spl_dir_object_dtor, NULL TSRMLS_CC);
-       retval.handlers = &spl_dir_handlers;
+       retval.handle = zend_objects_store_put(intern, spl_ce_dir_object_dtor, NULL TSRMLS_CC);
+       retval.handlers = &spl_ce_dir_handlers;
        return retval;
 }
 /* }}} */
 
-/* {{{ spl_dir_object_new */
-static zend_object_value spl_dir_object_new(zend_class_entry *class_type TSRMLS_DC)
+
+/* {{{ spl_ce_dir_object_new */
+/* See spl_ce_dir_object_new_ex */
+static zend_object_value spl_ce_dir_object_new(zend_class_entry *class_type TSRMLS_DC)
 {
-       spl_dir_object *tmp;
-       return spl_dir_object_new_ex(class_type, &tmp TSRMLS_CC);
+       spl_ce_dir_object *tmp;
+       return spl_ce_dir_object_new_ex(class_type, &tmp TSRMLS_CC);
 }
 /* }}} */
 
-/* {{{ spl_dir_open */
-static void spl_dir_open(spl_dir_object* intern, char *path TSRMLS_DC)
+
+/* {{{ spl_ce_dir_open */
+/* open a directory resource */
+static void spl_ce_dir_open(spl_ce_dir_object* intern, char *path TSRMLS_DC)
 {
-       /* we are using EH_THORW so REPORT_ERRORS results in exceptions */
        intern->dirp = php_stream_opendir(path, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
 
        intern->path = estrdup(path);
+       intern->index = 0;
 
        if (intern->dirp == NULL) {
                /* throw exception: should've been already happened */
@@ -135,20 +196,26 @@ static void spl_dir_open(spl_dir_object* intern, char *path TSRMLS_DC)
 }
 /* }}} */
 
-/* {{{ spl_dir_object_clone */
-static zend_object_value spl_dir_object_clone(zval *zobject TSRMLS_DC)
+/* {{{ spl_ce_dir_object_clone */
+/* Local zend_object_value creation (on stack)
+   Load the 'other' object 
+   Create a new empty object (See spl_ce_dir_object_new_ex)
+   Open the directory
+   Clone other members (properties)
+ */
+static zend_object_value spl_ce_dir_object_clone(zval *zobject TSRMLS_DC)
 {
        zend_object_value new_obj_val;
        zend_object *old_object;
        zend_object *new_object;
        zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
-       spl_dir_object *intern;
+       spl_ce_dir_object *intern;
 
        old_object = zend_objects_get_address(zobject TSRMLS_CC);
-       new_obj_val = spl_dir_object_new_ex(old_object->ce, &intern TSRMLS_CC);
+       new_obj_val = spl_ce_dir_object_new_ex(old_object->ce, &intern TSRMLS_CC);
        new_object = &intern->std;
 
-       spl_dir_open(intern, ((spl_dir_object*)old_object)->path TSRMLS_CC);
+       spl_ce_dir_open(intern, ((spl_ce_dir_object*)old_object)->path TSRMLS_CC);
 
        zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
 
@@ -156,32 +223,19 @@ static zend_object_value spl_dir_object_clone(zval *zobject TSRMLS_DC)
 }
 /* }}} */
 
-/* {{{ spl_dir_get_ce */
-static zend_class_entry *spl_dir_get_ce(zval *object TSRMLS_DC)
-{
-       return spl_ce_dir;
-}
-/* }}} */
-
-/* {{{ PHP_MINIT_FUNCTION(spl_directory) */
-PHP_MINIT_FUNCTION(spl_directory)
-{
-       REGISTER_SPL_STD_CLASS_EX(dir, spl_dir_object_new, spl_dir_class_functions);
-       REGISTER_SPL_IMPLEMENT(dir, sequence);
-       memcpy(&spl_dir_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
-       spl_dir_handlers.clone_obj = spl_dir_object_clone;
-       spl_dir_handlers.get_class_entry = spl_dir_get_ce;
-
-       return SUCCESS;
-}
-/* }}} */
-
-/* {{{ proto void __construct(string path)
+/* {{{ proto void DirectoryIterator::__construct(string path)
  Cronstructs a new dir iterator from a path. */
-SPL_CLASS_FUNCTION(dir, __construct)
+/* php_set_error_handling() is used to throw exceptions in case
+   the constructor fails. Here we use this to ensure the object
+   has a valid directory resource.
+   
+   When the constructor gets called the object is already created 
+   by the engine, so we must only call 'additional' initializations.
+ */
+SPL_METHOD(DirectoryIterator, __construct)
 {
        zval *object = getThis();
-       spl_dir_object *intern;
+       spl_ce_dir_object *intern;
        char *path;
        long len;
 
@@ -192,20 +246,21 @@ SPL_CLASS_FUNCTION(dir, __construct)
                return;
        }
 
-       intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
-       spl_dir_open(intern, path TSRMLS_CC);
+       intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       spl_ce_dir_open(intern, path TSRMLS_CC);
 
        php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
 }
 /* }}} */
 
-/* {{{ proto void rewind()
+/* {{{ proto void DirectoryIterator::rewind()
    Rewind dir back to the start */
-SPL_CLASS_FUNCTION(dir, rewind)
+SPL_METHOD(DirectoryIterator, rewind)
 {
        zval *object = getThis();
-       spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
 
+       intern->index = 0;
        if (intern->dirp) {
                php_stream_rewinddir(intern->dirp);
        }
@@ -215,14 +270,29 @@ SPL_CLASS_FUNCTION(dir, rewind)
 }
 /* }}} */
 
-/* {{{ proto string current()
+/* {{{ proto string DirectoryIterator::key()
    Return current dir entry */
-SPL_CLASS_FUNCTION(dir, current)
+SPL_METHOD(DirectoryIterator, key)
 {
        zval *object = getThis();
-       spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
 
        if (intern->dirp) {
+               RETURN_LONG(intern->index);
+       } else {
+               RETURN_FALSE;
+       }
+}
+/* }}} */
+
+/* {{{ proto string|false DirectoryIterator::current()
+   Return this (needed for Iterator interface) */
+SPL_METHOD(DirectoryIterator, current)
+{
+       zval *object = getThis();
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+       if (intern->entry.d_name[0]) {
                RETURN_STRING(intern->entry.d_name, 1);
        } else {
                RETURN_FALSE;
@@ -230,46 +300,383 @@ SPL_CLASS_FUNCTION(dir, current)
 }
 /* }}} */
 
-/* {{{ proto void next()
+/* {{{ proto void DirectoryIterator::next()
    Move to next entry */
-SPL_CLASS_FUNCTION(dir, next)
+SPL_METHOD(DirectoryIterator, next)
 {
        zval *object = getThis();
-       spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
 
+       intern->index++;
        if (!intern->dirp || !php_stream_readdir(intern->dirp, &intern->entry)) {
                intern->entry.d_name[0] = '\0';
        }
 }
 /* }}} */
 
-/* {{{ proto string hasMore()
+/* {{{ proto string DirectoryIterator::hasMore()
    Check whether dir contains more entries */
-SPL_CLASS_FUNCTION(dir, hasMore)
+SPL_METHOD(DirectoryIterator, hasMore)
 {
        zval *object = getThis();
-       spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
 
        RETURN_BOOL(intern->entry.d_name[0] != '\0');
 }
 /* }}} */
 
-/* {{{ proto string getPath()
+/* {{{ proto string DirectoryIterator::getPath()
    Return directory path */
-SPL_CLASS_FUNCTION(dir, getPath)
+SPL_METHOD(DirectoryIterator, getPath)
 {
        zval *object = getThis();
-       spl_dir_object *intern = (spl_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
 
        RETURN_STRING(intern->path, 1);
 }
 /* }}} */
 
+/* {{{ proto string DirectoryIterator::getFilename()
+   Return filename of current dir entry */
+SPL_METHOD(DirectoryIterator, getFilename)
+{
+       zval *object = getThis();
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+       RETURN_STRING(intern->entry.d_name, 1);
+}
+/* }}} */
+
+/* {{{ proto string DirectoryIterator::getPathname()
+   Return path and filename of current dir entry */
+SPL_METHOD(DirectoryIterator, getPathname)
+{
+       zval *object = getThis();
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+       char *filename;
+       int filename_len = spprintf(&filename, 0, "%s/%s", intern->path, intern->entry.d_name);
+       RETURN_STRINGL(filename, filename_len, 0);
+}
+/* }}} */
+
+/* {{{ proto string DirectoryTreeIterator::key()
+   Return path and filename of current dir entry */
+SPL_METHOD(DirectoryTreeIterator, key)
+{
+       zval *object = getThis();
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+       char *filename;
+       int filename_len = spprintf(&filename, 0, "%s/%s", intern->path, intern->entry.d_name);
+       RETURN_STRINGL(filename, filename_len, 0);
+}
+/* }}} */
+
+/* {{{ proto bool DirectoryIterator::isDot()
+   Returns true if current entry is '.' or  '..' */
+SPL_METHOD(DirectoryIterator, isDot)
+{
+       zval *object = getThis();
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+       RETURN_BOOL(!strcmp(intern->entry.d_name, ".") || !strcmp(intern->entry.d_name, ".."));
+}
+/* }}} */
+
+/* {{{ proto bool DirectoryIterator::isDir()
+   Returns whether current entry is a directory  */
+SPL_METHOD(DirectoryIterator, isDir)
+{
+       zval *object = getThis();
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       char *filename;
+       
+       php_stat_len filename_len = spprintf(&filename, 0, "%s/%s", intern->path, intern->entry.d_name);
+
+       php_stat(filename, filename_len, /*funcnum*/FS_IS_DIR, return_value TSRMLS_CC);
+
+       efree(filename);
+}
+/* }}} */
+
+/* {{{ proto bool DirectoryIterator::hasChildren()
+   Returns whether current entry is a directory and not '.' or '..' */
+SPL_METHOD(DirectoryTreeIterator, hasChildren)
+{
+       zval *object = getThis();
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       
+       if (!strcmp(intern->entry.d_name, ".") || !strcmp(intern->entry.d_name, "..")) {
+               RETURN_BOOL(0);
+       } else {
+               char *filename;
+               php_stat_len filename_len = spprintf(&filename, 0, "%s/%s", intern->path, intern->entry.d_name);
+
+               php_stat(filename, filename_len, FS_IS_DIR, return_value TSRMLS_CC);
+       efree(filename);
+    }
+}
+/* }}} */
+
+/* {{{ proto DirectoryIterator DirectoryIterator::getChildren()
+   Returns an iterator fo rthe current entry if it is a directory */
+SPL_METHOD(DirectoryTreeIterator, getChildren)
+{
+       zval *object = getThis(), zpath;
+       spl_ce_dir_object *intern = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+       
+       char *path;
+       int path_len = spprintf(&path, 0, "%s/%s", intern->path, intern->entry.d_name);
+       
+       ZVAL_STRINGL(&zpath, path, path_len, 0);
+
+       spl_instantiate_arg_ex1(spl_ce_DirectoryTreeIterator, &return_value, 0, &zpath TSRMLS_CC);
+       zval_dtor(&zpath);
+}
+/* }}} */
+
+/* define an overloaded iterator structure */
+typedef struct {
+       zend_object_iterator  intern;
+       zval                  *current;
+       spl_ce_dir_object       *object;
+} spl_ce_dir_it;
+
+/* forward declarations to the iterator handlers */
+static void spl_ce_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC);
+static int spl_ce_dir_it_has_more(zend_object_iterator *iter TSRMLS_DC);
+static void spl_ce_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
+static int spl_ce_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
+static void spl_ce_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC);
+static void spl_ce_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC);
+
+
+/* iterator handler table */
+zend_object_iterator_funcs spl_ce_dir_it_funcs = {
+       spl_ce_dir_it_dtor,
+       spl_ce_dir_it_has_more,
+       spl_ce_dir_it_current_data,
+       spl_ce_dir_it_current_key,
+       spl_ce_dir_it_move_forward,
+       spl_ce_dir_it_rewind
+};
+
+
+/* {{{ spl_ce_dir_get_iterator */
+zend_object_iterator *spl_ce_dir_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator   = emalloc(sizeof(spl_ce_dir_it));
+       spl_ce_dir_object   *dir_object = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+       object->refcount++;
+       iterator->intern.data = (void*)object;
+       iterator->intern.funcs = &spl_ce_dir_it_funcs;
+       MAKE_STD_ZVAL(iterator->current);
+       iterator->object = dir_object;
+       
+       return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+
+/* {{{ spl_ce_dir_it_dtor */
+static void spl_ce_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter;
+       zval        *intern = (zval*)iterator->intern.data;
+
+       zval_ptr_dtor(&iterator->current);
+       zval_ptr_dtor(&intern);
+
+       efree(iterator);
+}
+/* }}} */
+       
+
+/* {{{ spl_ce_dir_it_has_more */
+static int spl_ce_dir_it_has_more(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator = (spl_ce_dir_it *)iter;
+       spl_ce_dir_object   *object   = iterator->object;
+
+       return object->entry.d_name[0] != '\0' ? SUCCESS : FAILURE;
+}
+/* }}} */
+
+
+/* {{{ spl_ce_dir_it_current_data */
+static void spl_ce_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+       spl_ce_dir_it *iterator = (spl_ce_dir_it *)iter;
+       
+       *data = &iterator->current;
+}
+/* }}} */
+
+
+/* {{{ spl_ce_dir_it_current_key */
+static int spl_ce_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator = (spl_ce_dir_it *)iter;
+       spl_ce_dir_object   *object   = iterator->object;
+       
+       *int_key = object->index;
+       return HASH_KEY_IS_LONG;
+}
+/* }}} */
+
+
+/* {{{ spl_ce_dir_it_move_forward */
+static void spl_ce_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator = (spl_ce_dir_it *)iter;
+       spl_ce_dir_object   *object   = iterator->object;
+       
+       object->index++;
+       zval_dtor(iterator->current);
+       if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) {
+               object->entry.d_name[0] = '\0';
+               ZVAL_NULL(iterator->current);
+       } else {
+               ZVAL_STRING(iterator->current, object->entry.d_name, 1);
+       }
+}
+/* }}} */
+
+
+/* {{{ spl_ce_dir_it_rewind */
+static void spl_ce_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator = (spl_ce_dir_it *)iter;
+       spl_ce_dir_object   *object   = iterator->object;
+       
+       object->index = 0;
+       if (object->dirp) {
+               php_stream_rewinddir(object->dirp);
+       }
+       zval_dtor(iterator->current);
+       if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) {
+               object->entry.d_name[0] = '\0';
+               ZVAL_NULL(iterator->current);
+       } else {
+               ZVAL_STRING(iterator->current, object->entry.d_name, 1);
+       }
+}
+/* }}} */
+
+
+/* {{{ spl_ce_dir_tree_it_current_key */
+static int spl_ce_dir_tree_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator = (spl_ce_dir_it *)iter;
+       spl_ce_dir_object   *object   = iterator->object;
+       
+       *str_key_len = spprintf(str_key, 0, "%s/%s", object->path, object->entry.d_name) + 1;
+       return HASH_KEY_IS_STRING;
+}
+/* }}} */
+
+
+/* {{{ spl_ce_dir_tree_it_move_forward */
+static void spl_ce_dir_tree_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator = (spl_ce_dir_it *)iter;
+       spl_ce_dir_object   *object   = iterator->object;
+       
+       object->index++;
+       zval_dtor(iterator->current);
+skip_dots:
+       if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) {
+               object->entry.d_name[0] = '\0';
+               ZVAL_NULL(iterator->current);
+       } else {
+               if (!strcmp(object->entry.d_name, ".") || !strcmp(object->entry.d_name, "..")) {
+                       goto skip_dots;
+               }
+               ZVAL_STRING(iterator->current, object->entry.d_name, 1);
+       }
+}
+/* }}} */
+
+/* {{{ spl_ce_dir_tree_it_rewind */
+static void spl_ce_dir_tree_it_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator = (spl_ce_dir_it *)iter;
+       spl_ce_dir_object   *object   = iterator->object;
+       
+       object->index = 0;
+       if (object->dirp) {
+               php_stream_rewinddir(object->dirp);
+       }
+       zval_dtor(iterator->current);
+skip_dots:
+       if (!object->dirp || !php_stream_readdir(object->dirp, &object->entry)) {
+               object->entry.d_name[0] = '\0';
+               ZVAL_NULL(iterator->current);
+       } else {
+               if (!strcmp(object->entry.d_name, ".") || !strcmp(object->entry.d_name, "..")) {
+                       goto skip_dots;
+               }
+               ZVAL_STRING(iterator->current, object->entry.d_name, 1);
+       }
+}
+/* }}} */
+
+
+/* iterator handler table */
+zend_object_iterator_funcs spl_ce_dir_tree_it_funcs = {
+       spl_ce_dir_it_dtor,
+       spl_ce_dir_it_has_more,
+       spl_ce_dir_it_current_data,
+       spl_ce_dir_tree_it_current_key,
+       spl_ce_dir_tree_it_move_forward,
+       spl_ce_dir_tree_it_rewind
+};
+
+/* {{{ spl_ce_dir_get_iterator */
+zend_object_iterator *spl_ce_dir_tree_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
+{
+       spl_ce_dir_it       *iterator   = emalloc(sizeof(spl_ce_dir_it));
+       spl_ce_dir_object   *dir_object = (spl_ce_dir_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+       object->refcount++;
+       iterator->intern.data = (void*)object;
+       iterator->intern.funcs = &spl_ce_dir_tree_it_funcs;
+       MAKE_STD_ZVAL(iterator->current);
+       iterator->object = dir_object;
+       
+       return (zend_object_iterator*)iterator;
+}
+/* }}} */
+
+
+/* {{{ PHP_MINIT_FUNCTION(spl_directory)
+ */
+PHP_MINIT_FUNCTION(spl_directory)
+{
+       REGISTER_SPL_STD_CLASS_EX(DirectoryIterator, spl_ce_dir_object_new, spl_ce_dir_class_functions);
+       zend_class_implements(spl_ce_DirectoryIterator TSRMLS_CC, 1, zend_ce_iterator);
+       memcpy(&spl_ce_dir_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+       spl_ce_dir_handlers.clone_obj = spl_ce_dir_object_clone;
+
+       spl_ce_DirectoryIterator->get_iterator = spl_ce_dir_get_iterator;
+
+       REGISTER_SPL_SUB_CLASS_EX(DirectoryTreeIterator, DirectoryIterator, spl_ce_dir_object_new, spl_ce_dir_tree_class_functions);
+       REGISTER_SPL_IMPLEMENTS(DirectoryTreeIterator, RecursiveIterator);
+
+       spl_ce_DirectoryTreeIterator->get_iterator = spl_ce_dir_tree_get_iterator;
+
+       return SUCCESS;
+}
+/* }}} */
+
+
 /*
  * Local variables:
  * tab-width: 4
  * c-basic-offset: 4
  * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
  */
similarity index 86%
rename from ext/spl/spl_foreach.h
rename to ext/spl/spl_directory.h
index e27f9e77defdfa4a146abae80cc23441561a5f80..987bf7b074484016edc1b997afa746fddcef40a3 100755 (executable)
    +----------------------------------------------------------------------+
  */
 
-#ifndef SPL_FOREACH_H
-#define SPL_FOREACH_H
+#ifndef SPL_DIRECTORY_H
+#define SPL_DIRECTORY_H
 
 #include "php.h"
 #include "php_spl.h"
 
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET);
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH);
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE);
+extern zend_class_entry *spl_ce_DirectoryIterator;
 
-#endif /* SPL_FOREACH_H */
+PHP_MINIT_FUNCTION(spl_directory);
+
+#endif /* SPL_DIRECTORY_H */
 
 /*
  * Local Variables:
index 349a5997844a01aceaf9ef090993a8c287bd63bd..ec43c6fdd95b29671313883d44e3eab6f8bdf365 100755 (executable)
 #include "php.h"
 #include "php_ini.h"
 #include "ext/standard/info.h"
-#include "zend_compile.h"
+#include "zend_interfaces.h"
 
 #include "php_spl.h"
 #include "spl_functions.h"
 #include "spl_engine.h"
 
-/* {{{ spl_instanciate */
-void spl_instanciate(zend_class_entry *pce, zval **object TSRMLS_DC)
+#include "spl_array.h"
+
+/* {{{ spl_instantiate */
+void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC)
 {
-       ALLOC_ZVAL(*object);
+       if (alloc) {
+               ALLOC_ZVAL(*object);
+       }
        object_init_ex(*object, pce);
        (*object)->refcount = 1;
        (*object)->is_ref = 1; /* check if this can be hold always */
 }
 /* }}} */
 
-/* {{{ spl_instanciate_arg_ex2 */
-int spl_instanciate_arg_ex2(zend_class_entry *pce, zval **retval, zval *arg1, zval *arg2 TSRMLS_DC)
+/* {{{ spl_instantiate_arg_ex1 */
+int spl_instantiate_arg_ex1(zend_class_entry *pce, zval **retval, int alloc, zval *arg1 TSRMLS_DC)
 {
-       zval *object;
-       
-       spl_instanciate(pce, &object TSRMLS_CC);
+       zval *tmp;
        
-       retval = &EG(uninitialized_zval_ptr);
+       spl_instantiate(pce, retval, alloc TSRMLS_CC);
        
-       spl_call_method(&object, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), retval, 2, arg1, arg2 TSRMLS_CC);
-       *retval = object;
-       return 0;
-}
-/* }}} */
-
-/* {{{ spl_get_zval_ptr_ptr 
-   Remember to call spl_unlock_ptr_ptr when needed */
-zval ** spl_get_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC)
-{
-       if (node->op_type==IS_VAR) {
-               return T(node->u.var).var.ptr_ptr;
-       } else {
-               return NULL;
-       }
-}
-/* }}} */
-
-/* {{{ spl_unlock_zval_ptr_ptr */
-void spl_unlock_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC)
-{
-       if (node->op_type==IS_VAR) {
-               if (T(node->u.var).var.ptr_ptr) {
-                       spl_pzval_unlock_func(*T(node->u.var).var.ptr_ptr TSRMLS_CC);
-               } else if (T(node->u.var).EA.type==IS_STRING_OFFSET) {
-                       spl_pzval_unlock_func(T(node->u.var).EA.data.str_offset.str TSRMLS_CC);
-               }
+       zend_call_method(retval, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), &tmp, 1, arg1, NULL TSRMLS_CC);
+       if (tmp) {
+               zval_ptr_dtor(&tmp);
        }
+       return 0;
 }
 /* }}} */
 
-/* {{{ spl_get_zval_ptr */
-zval * spl_get_zval_ptr(znode *node, temp_variable *Ts, zval **should_free TSRMLS_DC)
+/* {{{ spl_instantiate_arg_ex2 */
+int spl_instantiate_arg_ex2(zend_class_entry *pce, zval **retval, int alloc, zval *arg1, zval *arg2 TSRMLS_DC)
 {
-       switch (node->op_type) {
-               case IS_CONST:
-                       *should_free = 0;
-                       return &node->u.constant;
-                       break;
-               case IS_TMP_VAR:
-                       return *should_free = &T(node->u.var).tmp_var;
-                       break;
-               case IS_VAR:
-                       if (T(node->u.var).var.ptr) {
-                               spl_pzval_unlock_func(T(node->u.var).var.ptr TSRMLS_CC);
-                               *should_free = 0;
-                               return T(node->u.var).var.ptr;
-                       } else {
-                               *should_free = &T(node->u.var).tmp_var;
-
-                               switch (T(node->u.var).EA.type) {
-                                       case IS_STRING_OFFSET: {
-                                                       temp_variable *T = &T(node->u.var);
-                                                       zval *str = T->EA.data.str_offset.str;
-
-                                                       if (T->EA.data.str_offset.str->type != IS_STRING
-                                                               || (T->EA.data.str_offset.offset<0)
-                                                               || (T->EA.data.str_offset.str->value.str.len <= T->EA.data.str_offset.offset)) {
-                                                               zend_error(E_NOTICE, "Uninitialized string offset:  %d", T->EA.data.str_offset.offset);
-                                                               T->tmp_var.value.str.val = empty_string;
-                                                               T->tmp_var.value.str.len = 0;
-                                                       } else {
-                                                               char c = str->value.str.val[T->EA.data.str_offset.offset];
-
-                                                               T->tmp_var.value.str.val = estrndup(&c, 1);
-                                                               T->tmp_var.value.str.len = 1;
-                                                       }
-                                                       spl_pzval_unlock_func(str TSRMLS_CC);
-                                                       T->tmp_var.refcount=1;
-                                                       T->tmp_var.is_ref=1;
-                                                       T->tmp_var.type = IS_STRING;
-                                                       return &T->tmp_var;
-                                               }
-                                               break;
-                               }
-                       }
-                       break;
-               case IS_UNUSED:
-                       *should_free = 0;
-                       return NULL;
-                       break;
-               EMPTY_SWITCH_DEFAULT_CASE()
+       zval *tmp;
+       
+       spl_instantiate(pce, retval, alloc TSRMLS_CC);
+       
+       zend_call_method(retval, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), &tmp, 2, arg1, arg2 TSRMLS_CC);
+       if (tmp) {
+               zval_ptr_dtor(&tmp);
        }
-       return NULL;
+       return 0;
 }
 /* }}} */
 
@@ -149,92 +87,6 @@ int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC)
 }
 /* }}} */
 
-/* {{{ spl_implements */
-spl_is_a spl_implements(zend_class_entry *ce)
-{
-       register spl_is_a is_a = 0;
-       register int i = ce->num_interfaces;
-       register zend_class_entry **pce = ce->interfaces;
-
-       while (i--) {
-               if (*pce == spl_ce_iterator)          is_a |= SPL_IS_A_ITERATOR;
-               else if (*pce == spl_ce_forward)      is_a |= SPL_IS_A_FORWARD;
-               else if (*pce == spl_ce_assoc)        is_a |= SPL_IS_A_ASSOC;
-               else if (*pce == spl_ce_sequence)     is_a |= SPL_IS_A_SEQUENCE;
-               else if (*pce == spl_ce_array_read)   is_a |= SPL_IS_A_ARRAY_READ;
-               else if (*pce == spl_ce_array_access) is_a |= SPL_IS_A_ARRAY_ACCESS;
-               pce++;
-       }
-       return is_a;
-}
-/* }}} */
-
-/* {{{ spl_call_method */
-zval * spl_call_method(zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int function_name_len, zval **retval_ptr, int param_count, zval* arg1, zval* arg2 TSRMLS_DC)
-{
-       int result;
-       zend_fcall_info fci;
-       zval z_fname;
-       zval *retval;
-
-       zval **params[2];
-
-       params[0] = &arg1;
-       params[1] = &arg2;
-
-       fci.size = sizeof(fci);
-       /*fci.function_table = NULL; will be read form zend_class_entry of object if needed */
-       fci.object_pp = object_pp;
-       fci.function_name = &z_fname;
-       fci.retval_ptr_ptr = retval_ptr ? retval_ptr : &retval;
-       fci.param_count = param_count;
-       fci.params = params;
-       fci.no_separation = 1;
-       fci.symbol_table = NULL;
-
-       if (!fn_proxy && !obj_ce) {
-               /* no interest in caching and no information already present that is
-                * needed later inside zend_call_function. */
-               ZVAL_STRINGL(&z_fname, function_name, function_name_len, 0);
-               result = zend_call_function(&fci, NULL TSRMLS_CC);
-       } else {
-               zend_fcall_info_cache fcic;
-
-               fcic.initialized = 1;
-               if (!obj_ce) {
-                       obj_ce = Z_OBJCE_PP(object_pp);
-               }
-               if (!fn_proxy || !*fn_proxy) {
-                       if (zend_hash_find(&obj_ce->function_table, function_name, function_name_len+1, (void **) &fcic.function_handler) == FAILURE) {
-                               /* error at c-level */
-                               zend_error(E_CORE_ERROR, "Couldn't find implementation for method %s::%s\n", obj_ce->name, function_name);
-                       }
-                       if (fn_proxy) {
-                               *fn_proxy = fcic.function_handler;
-                       }
-               } else {
-                       fcic.function_handler = *fn_proxy;
-               }
-               fcic.calling_scope = obj_ce;
-               fcic.object_pp = object_pp;
-               result = zend_call_function(&fci, &fcic TSRMLS_CC);
-       }
-       if (result == FAILURE) {
-               /* error at c-level */
-               if (!obj_ce) {
-                       obj_ce = Z_OBJCE_PP(object_pp);
-               }
-               zend_error(E_CORE_ERROR, "Couldn't execute method %s::%s\n", obj_ce->name, function_name);
-       }
-       if (!retval_ptr && retval) {
-               zval_dtor(retval);
-               FREE_ZVAL(retval);
-               return NULL;
-       }
-       return *retval_ptr;
-}
-/* }}} */
-
 /*
  * Local variables:
  * tab-width: 4
index 19f4ccc83b02d9052755ed0a85398aeb1abd8fc7..a753a9339e01cd44542a20a7c40084e1460581b8 100755 (executable)
 #include "php.h"
 #include "php_spl.h"
 
-#include "zend_compile.h"
-
-#undef EX
-#define EX(element) execute_data->element
-#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))
-#define T(offset) (*(temp_variable *)((char *) Ts + offset))
-
-#define NEXT_OPCODE()          \
-       EX(opline)++;                   \
-       return 0;
-
-zval * spl_call_method(zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int function_name_len, zval **retval_ptr, int param_count, zval* arg1, zval* arg2 TSRMLS_DC);
-
 /* {{{ zend_class_entry */
 static inline zend_class_entry *spl_get_class_entry(zval *obj TSRMLS_DC)
 {
@@ -55,46 +42,12 @@ static inline zend_class_entry *spl_get_class_entry(zval *obj TSRMLS_DC)
 #define spl_call_method_2(obj, obj_ce, fn_proxy, function_name, fname_len, retval, arg1, arg2) \
        spl_call_method(obj, obj_ce, fn_proxy, function_name, fname_len, retval, 2, arg1, arg2 TSRMLS_CC)
 
-void spl_instanciate(zend_class_entry *pce, zval **object TSRMLS_DC);
-int spl_instanciate_arg_ex2(zend_class_entry *pce, zval **retval, zval *arg1, zval *arg2 TSRMLS_DC);
-
-zval ** spl_get_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC);
-void spl_unlock_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC);
-zval * spl_get_zval_ptr(znode *node, temp_variable *Ts, zval **should_free TSRMLS_DC);
+void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC);
+int spl_instantiate_arg_ex1(zend_class_entry *pce, zval **retval, int alloc, zval *arg1 TSRMLS_DC);
+int spl_instantiate_arg_ex2(zend_class_entry *pce, zval **retval, int alloc, zval *arg1, zval *arg2 TSRMLS_DC);
 
 int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC);
 
-typedef enum {
-       SPL_IS_A_ITERATOR        = 0x01,
-       SPL_IS_A_FORWARD         = 0x02,
-       SPL_IS_A_ASSOC           = 0x04,
-       SPL_IS_A_SEQUENCE        = 0x08,
-       SPL_IS_A_ARRAY_READ      = 0x10,
-       SPL_IS_A_ARRAY_ACCESS    = 0x20
-} spl_is_a;
-
-spl_is_a spl_implements(zend_class_entry *ce);
-
-/* Use this only insode OPCODE-Hooks */
-static inline void spl_pzval_unlock_func(zval *z TSRMLS_DC)
-{
-       z->refcount--;
-       if (!z->refcount) {
-               z->refcount = 1;
-               z->is_ref = 0;
-               EG(garbage)[EG(garbage_ptr)++] = z;
-       }
-}
-
-/* Use this only insode OPCODE-Hooks */
-static inline void spl_pzval_lock_func(zval *z)
-{
-       z->refcount++;
-}
-
-/* Use this only insode OPCODE-Hooks */
-#define SELECTIVE_PZVAL_LOCK(pzv, pzn)         if (!((pzn)->u.EA.type & EXT_TYPE_UNUSED)) { spl_pzval_lock_func(pzv); }
-
 #endif /* SPL_ENGINE_H */
 
 /*
diff --git a/ext/spl/spl_foreach.c b/ext/spl/spl_foreach.c
deleted file mode 100755 (executable)
index 9044141..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
-   +----------------------------------------------------------------------+
-   | PHP Version 5                                                        |
-   +----------------------------------------------------------------------+
-   | Copyright (c) 1997-2003 The PHP Group                                |
-   +----------------------------------------------------------------------+
-   | This source file is subject to version 3.0 of the PHP license,       |
-   | that is bundled with this package in the file LICENSE, and is        |
-   | available through the world-wide-web at the following url:           |
-   | http://www.php.net/license/3_0.txt.                                  |
-   | If you did not receive a copy of the PHP license and are unable to   |
-   | obtain it through the world-wide-web, please send a note to          |
-   | license@php.net so we can mail you a copy immediately.               |
-   +----------------------------------------------------------------------+
-   | Authors: Marcus Boerger <helly@php.net>                              |
-   +----------------------------------------------------------------------+
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "zend_compile.h"
-
-#include "php_spl.h"
-#include "spl_functions.h"
-#include "spl_engine.h"
-#include "spl_foreach.h"
-
-#define OPTIMIZED_ARRAY_CONSTRUCT
-
-typedef struct {
-       zend_function      *next;
-       zend_function      *rewind;
-       zend_function      *more;
-       zend_function      *current;
-       zend_function      *key;
-} spl_foreach_funcs;
-
-typedef struct {
-       zval               *obj;
-       zend_class_entry   *obj_ce;
-       zend_uint          index;
-       spl_is_a           is_a;
-       spl_foreach_funcs  funcs;
-       char               dummy; /* needed for '\0' but we can't set it due to compiler optimizations */
-} spl_foreach_proxy;
-
-/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET) */
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET)
-{
-       zval **obj, *retval;
-       spl_foreach_proxy *proxy;
-       zend_class_entry *instance_ce, *obj_ce;
-       spl_is_a is_a;
-       temp_variable *tmp;
-
-       obj = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-
-       if (!obj || (instance_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) {
-               ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
-       }
-
-       is_a = spl_implements(instance_ce);
-
-       if (is_a & SPL_IS_A_ITERATOR) {
-               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-               obj_ce = instance_ce;
-               spl_call_method_0(obj, obj_ce, NULL, "newiterator", sizeof("newiterator")-1, &retval);
-               instance_ce = spl_get_class_entry(retval TSRMLS_CC);
-               is_a = spl_implements(instance_ce);
-               if (!(is_a & SPL_IS_A_FORWARD)) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Objects created by %s::newIterator() must implement spl_forward", obj_ce->name);
-                       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
-               }
-               spl_pzval_lock_func(retval);
-       } else if (is_a & SPL_IS_A_FORWARD) {
-               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-               retval = *obj;
-               retval->refcount += 2; /* lock two times */
-       } else {
-               ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
-       }
-
-       /* create the proxy */
-       proxy = emalloc(sizeof(spl_foreach_proxy));
-       proxy->obj = retval;
-       proxy->obj_ce = instance_ce;
-       proxy->index = 0;
-       proxy->is_a = is_a;
-       memset(&proxy->funcs, 0, sizeof(spl_foreach_funcs));
-       ((char*)proxy)[sizeof(spl_foreach_proxy)-1] = '\0';
-       /* And pack it into a zval. Since it is nowhere accessible using a 
-        * zval of type STRING is the fastest approach of storing the proxy.
-        */
-       ALLOC_ZVAL(retval);
-       ZVAL_STRINGL(retval, (char*)proxy, sizeof(spl_foreach_proxy)-1, 0);
-       retval->is_ref = 0;
-       retval->refcount = 2; /* lock two times */
-       /* return the created proxy container */
-       tmp = &EX_T(EX(opline)->result.u.var);
-       tmp->var.ptr = retval;
-       tmp->var.ptr_ptr = &tmp->var.ptr;
-
-       NEXT_OPCODE();
-}
-/* }}} */
-
-/* {{{ OPTIMIZED_ARRAY_CONSTRUCT macros */
-#ifdef OPTIMIZED_ARRAY_CONSTRUCT
-#define CONNECT_TO_BUCKET_DLLIST(element, list_head)           \
-       (element)->pNext = (list_head);                                                 \
-       (element)->pLast = NULL;
-
-#define CONNECT_TO_GLOBAL_DLLIST(element, ht)                          \
-       (element)->pListLast = (ht)->pListTail;                                 \
-       (ht)->pListTail = (element);                                                    \
-       (element)->pListNext = NULL;                                                    \
-       if ((element)->pListLast != NULL) {                                             \
-               (element)->pListLast->pListNext = (element);            \
-       }                                                                                                               \
-       if (!(ht)->pListHead) {                                                                 \
-               (ht)->pListHead = (element);                                            \
-       }                                                                                                               \
-       if ((ht)->pInternalPointer == NULL) {                                   \
-               (ht)->pInternalPointer = (element);                                     \
-       }
-#endif
-/* }}} */
-
-/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH) */
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH)
-{
-       znode *op1 = &EX(opline)->op1;
-       zval **obj = spl_get_zval_ptr_ptr(op1, EX(Ts) TSRMLS_CC);
-       zval *more, *value, *key, *result;
-       spl_foreach_proxy *proxy;
-
-       if (Z_TYPE_PP(obj) == IS_STRING) {
-               int has_more;
-
-               proxy = (spl_foreach_proxy*)Z_STRVAL_PP(obj);
-               obj = &proxy->obj; /* will be optimized out */
-
-               if (proxy->index++) {
-                       spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.next, "next", sizeof("next")-1, NULL);
-               } else {
-                       if (proxy->is_a & SPL_IS_A_SEQUENCE) {
-                               spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.rewind, "rewind", sizeof("rewind")-1, NULL);
-                       }
-                       /* now this is an optimization trick:
-                          ZEND_SWITCH_FREE receives the array copy or the spl object in op1 and has an unused op2
-                          We have to check for op1 being an object that implements spl_forwar... Or we simply set 
-                          op2 and know we can safely free the object as needed, which is waht we do. */
-                       op_array->opcodes[EX(opline)->op2.u.opline_num].op2 = *op1;
-               }
-
-               spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.more, "hasmore", sizeof("hasmore")-1, &more);
-               has_more = i_zend_is_true(more);
-               zval_dtor(more);
-               FREE_ZVAL(more);
-               if (has_more) {
-                       result = &EX_T(EX(opline)->result.u.var).tmp_var;
-
-                       spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.current, "current", sizeof("current")-1, &value);
-
-                       if (proxy->is_a & SPL_IS_A_ASSOC) {
-                               spl_call_method_0(obj, proxy->obj_ce, &proxy->funcs.key, "key", sizeof("key")-1, &key);
-                       } else {
-                               MAKE_STD_ZVAL(key);
-                               key->value.lval = proxy->index;
-                               key->type = IS_LONG;
-                       }
-#ifndef OPTIMIZED_ARRAY_CONSTRUCT
-                       array_init(result);
-                       add_next_index_zval(result, value);
-                       add_next_index_zval(result, key);
-#else
-                       {
-                               Bucket *p;
-                               HashTable *ht;
-
-                               ht = emalloc(sizeof(HashTable));
-                               result->value.ht = ht;
-                               ht->nTableSize = 1 << 1;
-                               ht->nTableMask = ht->nTableSize - 1;
-#if ZEND_DEBUG
-                               ht->inconsistent = 0; /*HT_OK;*/
-#endif
-                               
-                               ht->arBuckets = (Bucket **)emalloc(ht->nTableSize * sizeof(Bucket *));
-                               
-                               ht->pDestructor = ZVAL_PTR_DTOR;
-                               ht->pListHead = NULL;
-                               ht->pListTail = NULL;
-                               ht->nNumOfElements = 0;
-                               ht->nNextFreeElement = 0;
-                               ht->pInternalPointer = NULL;
-                               ht->persistent = 0;
-                               ht->nApplyCount = 0;
-                               ht->bApplyProtection = 1;
-                               result->type = IS_ARRAY;
-
-                               p = (Bucket*)emalloc(sizeof(Bucket)-1);
-                               p->pDataPtr = value;
-                               p->pData = &p->pDataPtr;
-                               p->nKeyLength = 0;
-                               p->h = 0;
-                               result->value.ht->arBuckets[0] = p;
-                               CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[0]);
-                               CONNECT_TO_GLOBAL_DLLIST(p, ht);
-
-                               p = (Bucket*)emalloc(sizeof(Bucket)-1);
-                               p->pDataPtr = key;
-                               p->pData = &p->pDataPtr;
-                               p->nKeyLength = 0;
-                               p->h = 1;
-                               result->value.ht->arBuckets[1] = p;
-                               CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[1]);
-                               CONNECT_TO_GLOBAL_DLLIST(p, ht);
-
-                               ht->nNumOfElements = 2;
-                       }
-#endif
-                       NEXT_OPCODE();
-               }
-               EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
-               return 0;
-       }
-       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_FETCH);
-}
-/* }}} */
-
-/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE) */
-ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE)
-{
-       /* See not in ZEND_FE_FETCH on setting op2 */
-       znode *op2 = &EX(opline)->op2;
-       zval *tmp, **obj = spl_get_zval_ptr_ptr(op2, EX(Ts) TSRMLS_CC);
-       spl_foreach_proxy *proxy;
-
-       if (obj) {
-               proxy = (spl_foreach_proxy*)Z_STRVAL_PP(obj);
-               tmp = *obj;
-               *obj = proxy->obj; /* restore */
-
-               efree(tmp->value.str.val);
-               FREE_ZVAL(tmp);
-
-               spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
-               spl_pzval_lock_func(*obj);
-               
-               SET_UNUSED(*op2);
-       }
-       ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_SWITCH_FREE);
-}
-/* }}} */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: fdm=marker
- * vim: noet sw=4 ts=4
- */
index 126a6f15e331a0922f919991bd3a2e11963d0615..415901d908814df7ce8b402663aff01dc2effcdf 100755 (executable)
@@ -24,7 +24,6 @@
 #include "php_ini.h"
 #include "ext/standard/info.h"
 #include "php_spl.h"
-#include "spl_foreach.h"
 
 /* {{{ spl_destroy_class */
 void spl_destroy_class(zend_class_entry ** ppce)
@@ -62,17 +61,24 @@ void spl_register_std_class(zend_class_entry ** ppce, char * class_name, void *
 }
 /* }}} */
 
-/* {{{ spl_register_parent_ce */
-void spl_register_parent_ce(zend_class_entry * class_entry, zend_class_entry * parent_class TSRMLS_DC)
+/* {{{ spl_register_sub_class */
+void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, void *obj_ctor, function_entry * function_list TSRMLS_DC)
 {
-       class_entry->parent = parent_class;
+       zend_class_entry ce;
+       
+       INIT_CLASS_ENTRY(ce, class_name, function_list);
+       ce.name_length = strlen(class_name);
+       *ppce = zend_register_internal_class_ex(&ce, parent_ce, NULL TSRMLS_CC);
+
+       /* entries changed by initialize */
+       (*ppce)->create_object = obj_ctor;
 }
 /* }}} */
 
-/* {{{ spl_register_implement */
-void spl_register_implement(zend_class_entry * class_entry, zend_class_entry * interface_entry TSRMLS_DC)
+/* {{{ spl_register_parent_ce */
+void spl_register_parent_ce(zend_class_entry * class_entry, zend_class_entry * parent_class TSRMLS_DC)
 {
-       zend_class_implements(class_entry TSRMLS_CC, 1, interface_entry);
+       class_entry->parent = parent_class;
 }
 /* }}} */
 
index 1a2aa1503755bf733cf5a5a0de3a7f87903cba84..99dfd7f1c8382c9746448c36ea7e313922aa8c25 100755 (executable)
 typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type TSRMLS_DC);
 
 #define REGISTER_SPL_STD_CLASS(class_name, obj_ctor) \
-       spl_register_std_class(&spl_ce_ ## class_name, "spl_" # class_name, obj_ctor, NULL TSRMLS_CC);
+       spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, NULL TSRMLS_CC);
 
 #define REGISTER_SPL_STD_CLASS_EX(class_name, obj_ctor, funcs) \
-       spl_register_std_class(&spl_ce_ ## class_name, "spl_" # class_name, obj_ctor, funcs TSRMLS_CC);
+       spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, funcs TSRMLS_CC);
+
+#define REGISTER_SPL_SUB_CLASS_EX(class_name, parent_class_name, obj_ctor, funcs) \
+       spl_register_sub_class(&spl_ce_ ## class_name, spl_ce_ ## parent_class_name, # class_name, obj_ctor, funcs TSRMLS_CC);
 
 #define REGISTER_SPL_INTERFACE(class_name) \
-       spl_register_interface(&spl_ce_ ## class_name, "spl_" # class_name, spl_funcs_ ## class_name TSRMLS_CC);
+       spl_register_interface(&spl_ce_ ## class_name, # class_name, spl_funcs_ ## class_name TSRMLS_CC);
 
 #define REGISTER_SPL_PARENT_CE(class_name, parent_class) \
        spl_register_parent_ce(spl_ce_ ## class_name, spl_ce_ ## parent_class TSRMLS_CC);
 
-#define REGISTER_SPL_IMPLEMENT(class_name, interface_name) \
-       spl_register_implement(spl_ce_ ## class_name, spl_ce_ ## interface_name TSRMLS_CC);
+#define REGISTER_SPL_IMPLEMENTS(class_name, interface_name) \
+       zend_class_implements(spl_ce_ ## class_name TSRMLS_CC, 1, spl_ce_ ## interface_name);
 
 #define REGISTER_SPL_FUNCTIONS(class_name, function_list) \
        spl_register_functions(spl_ce_ ## class_name, function_list TSRMLS_CC);
@@ -47,11 +50,11 @@ typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type T
 void spl_destroy_class(zend_class_entry ** ppce);
 
 void spl_register_std_class(zend_class_entry ** ppce, char * class_name, create_object_func_t ctor, function_entry * function_list TSRMLS_DC);
+void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, create_object_func_t ctor, function_entry * function_list TSRMLS_DC);
 
 void spl_register_interface(zend_class_entry ** ppce, char * class_name, zend_function_entry *functions TSRMLS_DC);
 
 void spl_register_parent_ce(zend_class_entry * class_entry, zend_class_entry * parent_class TSRMLS_DC);
-void spl_register_implement(zend_class_entry * class_entry, zend_class_entry * interface_entry TSRMLS_DC);
 void spl_register_functions(zend_class_entry * class_entry, function_entry * function_list TSRMLS_DC);
 void spl_register_property( zend_class_entry * class_entry, char *prop_name, zval *prop_val, int prop_flags TSRMLS_DC);
 
@@ -59,10 +62,13 @@ void spl_add_class_name(zval * list, zend_class_entry * pce TSRMLS_DC);
 void spl_add_interfaces(zval * list, zend_class_entry * pce TSRMLS_DC);
 int spl_add_classes(zend_class_entry ** ppce, zval *list TSRMLS_DC);
 
-#define SPL_CLASS_FE(class_name, function_name, arg_info, flags) \
+#define SPL_ME(class_name, function_name, arg_info, flags) \
        PHP_ME( spl_ ## class_name, function_name, arg_info, flags)
+       
+#define SPL_ABSTRACT_ME(class_name, arg_info, flags) \
+       ZEND_ABSTRACT_ME( spl_ ## class_name, arg_info, flags)
 
-#define SPL_CLASS_FUNCTION(class_name, function_name) \
+#define SPL_METHOD(class_name, function_name) \
        PHP_METHOD(spl_ ## class_name, function_name)
 
 #endif /* PHP_FUNCTIONS_H */
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
new file mode 100755 (executable)
index 0000000..8ee28fc
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2003 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license,       |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_0.txt.                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Marcus Boerger <helly@php.net>                              |
+   +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "zend_default_classes.h"
+#include "zend_interfaces.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_iterators.h"
+
+zend_class_entry *spl_ce_RecursiveIterator;
+zend_class_entry *spl_ce_RecursiveIteratorIterator;
+
+function_entry spl_funcs_RecursiveIterator[] = {
+       SPL_ABSTRACT_ME(RecursiveIterator, hasChildren,  NULL)
+       SPL_ABSTRACT_ME(RecursiveIterator, getChildren,  NULL)
+       {NULL, NULL, NULL}
+};
+
+SPL_METHOD(RecursiveIteratorIterator, __construct);
+SPL_METHOD(RecursiveIteratorIterator, rewind);
+SPL_METHOD(RecursiveIteratorIterator, hasMore);
+SPL_METHOD(RecursiveIteratorIterator, key);
+SPL_METHOD(RecursiveIteratorIterator, current);
+SPL_METHOD(RecursiveIteratorIterator, next);
+SPL_METHOD(RecursiveIteratorIterator, getLevel);
+
+static
+ZEND_BEGIN_ARG_INFO(arginfo_recursive_it___construct, 0) 
+       ZEND_ARG_INFO(0, iterator)  /* parameter name */
+ZEND_END_ARG_INFO();
+
+static zend_function_entry spl_funcs_RecursiveIteratorIterator[] = {
+       SPL_ME(RecursiveIteratorIterator, __construct,   arginfo_recursive_it___construct, ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, rewind,        NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, hasMore,       NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, key,           NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, current,       NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, next,          NULL, ZEND_ACC_PUBLIC)
+       SPL_ME(RecursiveIteratorIterator, getLevel,      NULL, ZEND_ACC_PUBLIC)
+       {NULL, NULL, NULL}
+};
+
+typedef struct _spl_sub_iterator {
+       zend_object_iterator    *iterator;
+       zval                    *zobject;
+       zend_class_entry        *ce;
+} spl_sub_iterator;
+
+typedef struct _spl_recursive_it_object {
+       zend_object              std;
+       spl_sub_iterator         *iterators;
+       int                      level;
+} spl_recursive_it_object;
+
+typedef struct _spl_recursive_it_iterator {
+       zend_object_iterator   intern;
+       zval                   *zobject;
+} spl_recursive_it_iterator;
+
+static zend_object_handlers spl_handlers_RecursiveIteratorIterator;
+
+static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC)
+{
+       spl_recursive_it_iterator *iter   = (spl_recursive_it_iterator*)_iter;
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)_iter->data;
+       zend_object_iterator      *sub_iter;
+
+       while (object->level) {
+               sub_iter = object->iterators[object->level].iterator;
+               sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
+               zval_ptr_dtor(&object->iterators[object->level--].zobject);
+       }
+       erealloc(object->iterators, sizeof(spl_sub_iterator));
+       object->level = 0;
+
+       zval_ptr_dtor(&iter->zobject);  
+       efree(iter);
+}
+       
+static int spl_recursive_it_has_more_ex(spl_recursive_it_object *object TSRMLS_DC)
+{
+       zend_object_iterator      *sub_iter;
+       int                       level = object->level;
+       
+       while (level >=0) {
+               sub_iter = object->iterators[level].iterator;
+               if (sub_iter->funcs->has_more(sub_iter TSRMLS_CC) == SUCCESS) {
+                       return SUCCESS;
+               }
+               level--;
+       }
+       return FAILURE;
+}
+
+static int spl_recursive_it_has_more(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
+       
+       return spl_recursive_it_has_more_ex(object TSRMLS_CC);
+}
+
+static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
+       zend_object_iterator      *sub_iter = object->iterators[object->level].iterator;
+       
+       return sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC);
+}
+
+static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)iter->data;
+       zend_object_iterator      *sub_iter = object->iterators[object->level].iterator;
+
+       if (sub_iter->funcs->get_current_key) {
+               return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC);
+       } else {
+               *int_key = iter->index;
+               return HASH_KEY_IS_LONG;
+       }
+}
+
+static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object TSRMLS_DC)
+{
+       zend_object_iterator      *iterator;
+       zval                      *zobject;
+       zend_class_entry          *ce;
+       zval                      *retval, *child;
+       zend_object_iterator      *sub_iter;
+
+       while (1) {
+               iterator = object->iterators[object->level].iterator;
+               iterator->funcs->move_forward(iterator TSRMLS_CC);
+               if (iterator->funcs->has_more(iterator TSRMLS_CC) == SUCCESS) {
+                       zobject = object->iterators[object->level].zobject;
+                       ce = object->iterators[object->level].ce;
+                       zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
+                       if (zend_is_true(retval)) {
+                               zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child);
+                               ce = Z_OBJCE_P(child);
+                               if (!ce || !instanceof_function(ce, spl_ce_RecursiveIterator TSRMLS_CC)) {
+                                       zend_throw_exception(zend_exception_get_default(), "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC);
+                                       zval_ptr_dtor(&retval);
+                                       return;
+                               }
+                               object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
+                               sub_iter = ce->get_iterator(ce, child TSRMLS_CC);
+                               if (sub_iter->funcs->rewind) {
+                                       sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
+                               }
+                               object->iterators[object->level].iterator = sub_iter;
+                               object->iterators[object->level].zobject = child;
+                               object->iterators[object->level].ce = ce;
+                       }
+                       zval_ptr_dtor(&retval);
+                       return; /* return the element */
+               }
+               /* no more elements */
+               if (object->level > 0) {
+                       iterator->funcs->dtor(iterator TSRMLS_CC);
+                       zval_ptr_dtor(&object->iterators[object->level].zobject);
+                       object->level--;
+               } else {
+                       return; /* done completeley */
+               }
+       }
+}
+
+static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object TSRMLS_DC)
+{
+       zend_object_iterator      *sub_iter;
+
+       while (object->level) {
+               sub_iter = object->iterators[object->level].iterator;
+               sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
+               zval_ptr_dtor(&object->iterators[object->level--].zobject);
+       }
+       erealloc(object->iterators, sizeof(spl_sub_iterator));
+       sub_iter = object->iterators[0].iterator;
+       if (sub_iter->funcs->rewind) {
+               sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
+       }
+}
+
+static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_recursive_it_move_forward_ex((spl_recursive_it_object*)iter->data TSRMLS_CC);
+}
+
+static void spl_recursive_it_rewind(zend_object_iterator *iter TSRMLS_DC)
+{
+       spl_recursive_it_rewind_ex((spl_recursive_it_object*)iter->data TSRMLS_CC);
+}
+
+static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject TSRMLS_DC)
+{
+       spl_recursive_it_iterator *iterator = emalloc(sizeof(spl_recursive_it_iterator));
+       spl_recursive_it_object   *object   = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC);
+
+       zobject->refcount++;
+       iterator->intern.data = (void*)object;
+       iterator->intern.funcs = ce->iterator_funcs.funcs;
+       iterator->zobject = zobject;
+       return (zend_object_iterator*)iterator;
+}
+
+zend_object_iterator_funcs spl_recursive_it_iterator_funcs = {
+       spl_recursive_it_dtor,
+       spl_recursive_it_has_more,
+       spl_recursive_it_get_current_data,
+       spl_recursive_it_get_current_key,
+       spl_recursive_it_move_forward,
+       spl_recursive_it_rewind
+};
+
+SPL_METHOD(RecursiveIteratorIterator, __construct)
+{
+       zval                      *object = getThis();
+       spl_recursive_it_object   *intern;
+       zval                      *iterator;
+       zend_class_entry          *ce_iterator;
+
+       php_set_error_handling(EH_THROW, zend_exception_get_default() TSRMLS_CC);
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &iterator, spl_ce_RecursiveIterator) == FAILURE) {
+               php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+               return;
+       }
+
+       intern = (spl_recursive_it_object*)zend_object_store_get_object(object TSRMLS_CC);
+       intern->iterators = emalloc(sizeof(spl_sub_iterator));
+       intern->level = 0;
+       ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */
+       intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator TSRMLS_CC);
+       intern->iterators[0].zobject = iterator;
+       intern->iterators[0].ce = ce_iterator;
+
+       php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+}
+
+SPL_METHOD(RecursiveIteratorIterator, rewind)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       spl_recursive_it_rewind_ex(object TSRMLS_CC);
+}
+
+SPL_METHOD(RecursiveIteratorIterator, hasMore)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       RETURN_BOOL(spl_recursive_it_has_more_ex(object TSRMLS_CC) == SUCCESS);
+}
+
+SPL_METHOD(RecursiveIteratorIterator, key)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+       zend_object_iterator      *iterator = object->iterators[object->level].iterator;
+
+       if (iterator->funcs->get_current_key) {
+               char *str_key;
+               uint str_key_len;
+               ulong int_key;
+               if (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC) == HASH_KEY_IS_LONG) {
+                       RETURN_LONG(int_key);
+               } else {
+                       RETURN_STRINGL(str_key, str_key_len, 1);
+               }
+       } else {
+               RETURN_NULL();
+       }
+}
+
+SPL_METHOD(RecursiveIteratorIterator, current)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+       zend_object_iterator      *iterator = object->iterators[object->level].iterator;
+       zval                      **data;
+
+       iterator->funcs->get_current_data(iterator, &data TSRMLS_CC);
+       *return_value = **data;
+       return_value->refcount++;
+}
+
+SPL_METHOD(RecursiveIteratorIterator, next)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+       spl_recursive_it_move_forward_ex(object TSRMLS_CC);
+}
+
+SPL_METHOD(RecursiveIteratorIterator, getLevel)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+       
+       RETURN_LONG(object->level);
+}
+
+/* {{{ spl_dtor_RecursiveIteratorIterator */
+static void spl_dtor_RecursiveIteratorIterator(void *_object, zend_object_handle handle TSRMLS_DC)
+{
+       spl_recursive_it_object   *object = (spl_recursive_it_object *)_object;
+       zend_object_iterator      *sub_iter;
+
+       if (object->iterators) {
+               while (object->level >= 0) {
+                       sub_iter = object->iterators[object->level].iterator;
+                       sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
+                       zval_ptr_dtor(&object->iterators[object->level--].zobject);
+               }
+               efree(object->iterators);
+       }
+
+       zend_hash_destroy(object->std.properties);
+       FREE_HASHTABLE(object->std.properties);
+
+       efree(object);
+}
+/* }}} */
+
+static int spl_recursive_it_gets_implemented(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC)
+{
+       return SUCCESS;
+}
+
+/* {{{ spl_new_RecursiveIteratorIterator */
+static zend_object_value spl_new_RecursiveIteratorIterator(zend_class_entry *class_type TSRMLS_DC)
+{
+       zend_object_value retval;
+       spl_recursive_it_object *intern;
+       zval *tmp;
+
+       intern = emalloc(sizeof(spl_recursive_it_object));
+       memset(intern, 0, sizeof(spl_recursive_it_object));
+       intern->std.ce = class_type;
+
+       ALLOC_HASHTABLE(intern->std.properties);
+       zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+       zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+       retval.handle = zend_objects_store_put(intern, spl_dtor_RecursiveIteratorIterator, NULL TSRMLS_CC);
+       retval.handlers = &spl_handlers_RecursiveIteratorIterator;
+       return retval;
+}
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION(spl_iterators)
+ */
+PHP_MINIT_FUNCTION(spl_iterators)
+{
+       REGISTER_SPL_INTERFACE(RecursiveIterator);
+       zend_class_implements(spl_ce_RecursiveIterator TSRMLS_CC, 1, zend_ce_iterator);
+
+       REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_new_RecursiveIteratorIterator, spl_funcs_RecursiveIteratorIterator);
+       zend_class_implements(spl_ce_RecursiveIteratorIterator TSRMLS_CC, 1, zend_ce_iterator);
+       memcpy(&spl_handlers_RecursiveIteratorIterator, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+       spl_handlers_RecursiveIteratorIterator.clone_obj = NULL;
+       
+       spl_ce_RecursiveIterator->interface_gets_implemented = spl_recursive_it_gets_implemented;
+
+       spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
+       spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs;
+
+       return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h
new file mode 100755 (executable)
index 0000000..c694d6d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2003 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license,       |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_0.txt.                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Marcus Boerger <helly@php.net>                              |
+   +----------------------------------------------------------------------+
+ */
+
+#ifndef SPL_ITERATORS_H
+#define SPL_ITERATORS_H
+
+#include "php.h"
+#include "php_spl.h"
+
+extern zend_class_entry *spl_ce_RecursiveIterator;
+extern zend_class_entry *spl_ce_RecursiveIteratorIterator;
+
+PHP_MINIT_FUNCTION(spl_iterators);
+
+#endif /* SPL_ITERATORS_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */