summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Boerger <helly@php.net>2003-11-09 14:05:36 +0000
committerMarcus Boerger <helly@php.net>2003-11-09 14:05:36 +0000
commit159c538bcf7cc649410a7e91b11584dcebcf1b55 (patch)
tree2e5d3063aaf3733744fa81a1614fd526f9881be1
parent44dc9eb3e4ae8be3d3d187b8e6335d768447fed5 (diff)
downloadphp-git-159c538bcf7cc649410a7e91b11584dcebcf1b55.tar.gz
Major update:
- 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
-rwxr-xr-xext/spl/config.m435
-rwxr-xr-xext/spl/examples/directoryfilterdots.inc26
-rwxr-xr-xext/spl/examples/directorytree.inc10
-rwxr-xr-xext/spl/examples/directorytree.php17
-rwxr-xr-xext/spl/examples/filter.inc16
-rwxr-xr-xext/spl/examples/filteriterator.inc89
-rwxr-xr-xext/spl/examples/findfile.php17
-rwxr-xr-xext/spl/examples/limititerator.inc48
-rwxr-xr-xext/spl/examples/recursiveiteratoriterator.inc87
-rwxr-xr-xext/spl/examples/searchiterator.inc16
-rwxr-xr-xext/spl/php_spl.c124
-rwxr-xr-xext/spl/php_spl.h12
-rwxr-xr-xext/spl/spl_array.c402
-rwxr-xr-xext/spl/spl_array.h14
-rwxr-xr-xext/spl/spl_directory.c577
-rwxr-xr-xext/spl/spl_directory.h (renamed from ext/spl/spl_foreach.h)12
-rwxr-xr-xext/spl/spl_engine.c200
-rwxr-xr-xext/spl/spl_engine.h53
-rwxr-xr-xext/spl/spl_foreach.c269
-rwxr-xr-xext/spl/spl_functions.c20
-rwxr-xr-xext/spl/spl_functions.h22
-rwxr-xr-xext/spl/spl_iterators.c399
-rwxr-xr-xext/spl/spl_iterators.h39
23 files changed, 1405 insertions, 1099 deletions
diff --git a/ext/spl/config.m4 b/ext/spl/config.m4
index bce2b4f43a..95bffc35c1 100755
--- a/ext/spl/config.m4
+++ b/ext/spl/config.m4
@@ -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
index 0000000000..3ca0e6a2f8
--- /dev/null
+++ b/ext/spl/examples/directoryfilterdots.inc
@@ -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
index 0000000000..218ca513d9
--- /dev/null
+++ b/ext/spl/examples/directorytree.inc
@@ -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
index 0000000000..744a17a99a
--- /dev/null
+++ b/ext/spl/examples/directorytree.php
@@ -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
diff --git a/ext/spl/examples/filter.inc b/ext/spl/examples/filter.inc
index 1cab580edd..d01dd62845 100755
--- a/ext/spl/examples/filter.inc
+++ b/ext/spl/examples/filter.inc
@@ -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
index 0000000000..43f8515c2f
--- /dev/null
+++ b/ext/spl/examples/filteriterator.inc
@@ -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
index 0000000000..003111e272
--- /dev/null
+++ b/ext/spl/examples/findfile.php
@@ -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
index 0000000000..c1a19fedd9
--- /dev/null
+++ b/ext/spl/examples/limititerator.inc
@@ -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
index 0000000000..95d52d7f76
--- /dev/null
+++ b/ext/spl/examples/recursiveiteratoriterator.inc
@@ -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
index 0000000000..42c249be9b
--- /dev/null
+++ b/ext/spl/examples/searchiterator.inc
@@ -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
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 7617f3fa9e..c5941d7c07 100755
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -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);
}
/* }}} */
diff --git a/ext/spl/php_spl.h b/ext/spl/php_spl.h
index b8de833022..474da85c01 100755
--- a/ext/spl/php_spl.h
+++ b/ext/spl/php_spl.h
@@ -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 */
/*
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index 95132cb6c2..6df776ac6c 100755
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -23,317 +23,74 @@
#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);
diff --git a/ext/spl/spl_array.h b/ext/spl/spl_array.h
index 840a9627eb..d4bc03d876 100755
--- a/ext/spl/spl_array.h
+++ b/ext/spl/spl_array.h
@@ -22,16 +22,12 @@
#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 */
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index 045e5d4368..444ac26704 100755
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -27,51 +27,97 @@
#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
*/
diff --git a/ext/spl/spl_foreach.h b/ext/spl/spl_directory.h
index e27f9e77de..987bf7b074 100755
--- a/ext/spl/spl_foreach.h
+++ b/ext/spl/spl_directory.h
@@ -16,17 +16,17 @@
+----------------------------------------------------------------------+
*/
-#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:
diff --git a/ext/spl/spl_engine.c b/ext/spl/spl_engine.c
index 349a599784..ec43c6fdd9 100755
--- a/ext/spl/spl_engine.c
+++ b/ext/spl/spl_engine.c
@@ -23,115 +23,53 @@
#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
diff --git a/ext/spl/spl_engine.h b/ext/spl/spl_engine.h
index 19f4ccc83b..a753a9339e 100755
--- a/ext/spl/spl_engine.h
+++ b/ext/spl/spl_engine.h
@@ -22,19 +22,6 @@
#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
index 90441415d8..0000000000
--- a/ext/spl/spl_foreach.c
+++ /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
- */
diff --git a/ext/spl/spl_functions.c b/ext/spl/spl_functions.c
index 126a6f15e3..415901d908 100755
--- a/ext/spl/spl_functions.c
+++ b/ext/spl/spl_functions.c
@@ -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;
}
/* }}} */
diff --git a/ext/spl/spl_functions.h b/ext/spl/spl_functions.h
index 1a2aa15037..99dfd7f1c8 100755
--- a/ext/spl/spl_functions.h
+++ b/ext/spl/spl_functions.h
@@ -24,19 +24,22 @@
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
index 0000000000..8ee28fc745
--- /dev/null
+++ b/ext/spl/spl_iterators.c
@@ -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
index 0000000000..c694d6da67
--- /dev/null
+++ b/ext/spl/spl_iterators.h
@@ -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
+ */