summaryrefslogtreecommitdiff
path: root/ext/spl
diff options
context:
space:
mode:
authorMarcus Boerger <helly@php.net>2003-05-01 23:28:28 +0000
committerMarcus Boerger <helly@php.net>2003-05-01 23:28:28 +0000
commitb5a70a72d13a3951317466cb8a671eafffffc359 (patch)
tree09f1ec55eca84f6c7bd183415b3999e78311d703 /ext/spl
parent0d46a490f7abc6039fd98afc3c0a62ce111551c8 (diff)
downloadphp-git-b5a70a72d13a3951317466cb8a671eafffffc359.tar.gz
Add spl extension
Diffstat (limited to 'ext/spl')
-rwxr-xr-xext/spl/CREDITS2
-rwxr-xr-xext/spl/EXPERIMENTAL0
-rwxr-xr-xext/spl/TODO13
-rwxr-xr-xext/spl/config.m441
-rwxr-xr-xext/spl/examples/dba_dump.php72
-rwxr-xr-xext/spl/php_spl.c310
-rwxr-xr-xext/spl/php_spl.h114
-rwxr-xr-xext/spl/spl.php306
-rwxr-xr-xext/spl/spl_array.c349
-rwxr-xr-xext/spl/spl_array.h49
-rwxr-xr-xext/spl/spl_engine.c223
-rwxr-xr-xext/spl/spl_engine.h63
-rwxr-xr-xext/spl/spl_foreach.c130
-rwxr-xr-xext/spl/spl_foreach.h37
-rwxr-xr-xext/spl/spl_functions.c187
-rwxr-xr-xext/spl/spl_functions.h80
-rwxr-xr-xext/spl/tests/.htaccess3
-rwxr-xr-xext/spl/tests/array_access_001.phpt127
-rwxr-xr-xext/spl/tests/array_access_002.phpt137
-rwxr-xr-xext/spl/tests/array_access_ex.phpt154
-rwxr-xr-xext/spl/tests/array_read.phpt208
-rwxr-xr-xext/spl/tests/foreach.phpt184
-rwxr-xr-xext/spl/tests/forward.phpt115
-rwxr-xr-xext/spl/tests/sequence.phpt138
24 files changed, 3042 insertions, 0 deletions
diff --git a/ext/spl/CREDITS b/ext/spl/CREDITS
new file mode 100755
index 0000000000..8710aac550
--- /dev/null
+++ b/ext/spl/CREDITS
@@ -0,0 +1,2 @@
+SPL
+Marcus Boerger
diff --git a/ext/spl/EXPERIMENTAL b/ext/spl/EXPERIMENTAL
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/ext/spl/EXPERIMENTAL
diff --git a/ext/spl/TODO b/ext/spl/TODO
new file mode 100755
index 0000000000..5311ef6c11
--- /dev/null
+++ b/ext/spl/TODO
@@ -0,0 +1,13 @@
+This is the ToDo of ext/spl:
+
+- spl::array_access cals set() which is supposed to return a value.
+ Currently you *must* return a value even when it is not used.
+ $obj[$idx] = $val; // doesn't use the return value
+ $x = $obj[$idx] = $val; // here it is used
+ Since array_access.phpt is a test with a return value there
+ should be a test without a return value. Maybe an error message
+ is required in case there is no return value.
+
+- spl::array_access_ex is not completely done and not tested.
+
+If you have further questions: mailto:helly@php.net
diff --git a/ext/spl/config.m4 b/ext/spl/config.m4
new file mode 100755
index 0000000000..bcae05f2fb
--- /dev/null
+++ b/ext/spl/config.m4
@@ -0,0 +1,41 @@
+dnl $Id$
+dnl config.m4 for extension SPL
+
+PHP_ARG_ENABLE(spl, enable SPL suppport,
+[ --enable-spl Enable Standard PHP Library])
+
+dnl first enable/disable all hooks
+
+PHP_ARG_ENABLE(spl, enable all hooks,
+[ --enable-spl-hook-all SPL: Enable all hooks])
+
+dnl now all single enable/disable for hooks
+
+PHP_ARG_ENABLE(spl, enable hook on foreach,
+[ --disable-spl-foreach SPL: Disable hook on forach], yes)
+
+PHP_ARG_ENABLE(spl, enable hook on array read,
+[ --enable-spl-array-read SPL: Enable hook on array read])
+
+PHP_ARG_ENABLE(spl, 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_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
+
+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, $ext_shared)
+fi
diff --git a/ext/spl/examples/dba_dump.php b/ext/spl/examples/dba_dump.php
new file mode 100755
index 0000000000..d32f1761c9
--- /dev/null
+++ b/ext/spl/examples/dba_dump.php
@@ -0,0 +1,72 @@
+<?php
+
+/* dba dump utility
+ *
+ * Usage php dba_dump <file> <handler>
+ *
+ * Note: configure with --enable-dba
+ */
+
+class dba_reader implements spl::iterator {
+
+ public $db = NULL;
+
+ function __construct($file, $handler) {
+ $this->db = dba_open($file, 'r', $handler);
+ }
+
+ function new_iterator() {
+ return new dba_iter($this);
+ }
+
+ function __destruct() {
+ if ($this->db) {
+ dba_close($this->db);
+ }
+ }
+}
+
+class dba_iter implements spl::sequence_assoc {
+
+ private $obj;
+ private $key = NULL;
+ private $val = NULL;
+
+ function __construct($obj) {
+ $this->obj = $obj;
+ }
+
+ function reset() {
+ if ($this->obj->db) {
+ $this->key = dba_firstkey($this->obj->db);
+ }
+ }
+
+ function elem() {
+ return $this->val;
+ }
+
+ function next() {
+ $this->key = dba_nextkey($this->obj->db);
+ }
+
+ function more() {
+ if ($this->obj->db && $this->key !== false) {
+ $this->val = dba_fetch($this->key, $this->obj->db);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function key() {
+ return $this->key;
+ }
+}
+
+$db = new dba_reader($argv[1], $argv[2]);
+foreach($db as $key => $val) {
+ echo "'$key' => '$val'\n";
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
new file mode 100755
index 0000000000..b97c44f32c
--- /dev/null
+++ b/ext/spl/php_spl.c
@@ -0,0 +1,310 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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 "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_foreach.h"
+#include "spl_array.h"
+
+#ifdef COMPILE_DL_SPL
+ZEND_GET_MODULE(spl)
+#endif
+
+ZEND_DECLARE_MODULE_GLOBALS(spl)
+
+/* {{{ spl_functions
+ */
+function_entry spl_functions[] = {
+ PHP_FE(spl_classes, NULL)
+ PHP_FE(class_name, NULL)
+ PHP_FE(class_parents, NULL)
+ PHP_FE(class_implements, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ spl_module_entry
+ */
+zend_module_entry spl_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "spl",
+ spl_functions,
+ PHP_MINIT(spl),
+ PHP_MSHUTDOWN(spl),
+ PHP_RINIT(spl),
+ PHP_RSHUTDOWN(spl),
+ PHP_MINFO(spl),
+ "0.1",
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+zend_namespace *spl_ns_spl;
+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_array_read;
+zend_class_entry *spl_ce_array_access;
+zend_class_entry *spl_ce_array_access_ex;
+zend_class_entry *spl_ce_array_writer;
+#ifdef SPL_ARRAY_WRITE
+zend_class_entry *spl_ce_array_writer_default;
+#endif /* SPL_ARRAY_WRITE */
+
+/* {{{ spl_functions_none
+ */
+function_entry spl_functions_none[] = {
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+static unsigned char first_of_two_force_ref[] = { 2, BYREF_FORCE, BYREF_NONE };
+
+/* {{{ spl_array_writer_funcs
+ */
+function_entry spl_array_writer_funcs[] = {
+ SPL_CLASS_FE(array_writer_default, __construct, first_of_two_force_ref)
+ SPL_CLASS_FE(array_writer_default, set, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ spl_init_globals
+ */
+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);
+#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);
+#endif /* SPL_ARRAY_WRITE */
+}
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION(spl)
+ */
+PHP_MINIT_FUNCTION(spl)
+{
+ ZEND_INIT_MODULE_GLOBALS(spl, spl_init_globals, NULL);
+
+ REGISTER_SPL_NAMESPACE(spl);
+
+ REGISTER_SPL_INTERFACE(spl, iterator);
+ REGISTER_SPL_INTF_FUNC(spl, iterator, new_iterator);
+
+ REGISTER_SPL_INTERFACE(spl, forward);
+ REGISTER_SPL_INTF_FUNC(spl, forward, current);
+ REGISTER_SPL_INTF_FUNC(spl, forward, next);
+ REGISTER_SPL_INTF_FUNC(spl, forward, more);
+
+ REGISTER_SPL_INTERFACE(spl, sequence);
+ REGISTER_SPL_INTF_FUNC(spl, sequence, rewind);
+ REGISTER_SPL_PARENT_CE(spl, sequence, forward);
+
+ REGISTER_SPL_INTERFACE(spl, assoc);
+ REGISTER_SPL_INTF_FUNC(spl, assoc, key);
+
+ REGISTER_SPL_INTERFACE(spl, forward_assoc);
+ REGISTER_SPL_PARENT_CE(spl, forward_assoc, forward);
+ REGISTER_SPL_IMPLEMENT(spl, forward_assoc, assoc);
+
+ REGISTER_SPL_INTERFACE(spl, sequence_assoc);
+ REGISTER_SPL_PARENT_CE(spl, sequence_assoc, sequence);
+ REGISTER_SPL_IMPLEMENT(spl, sequence_assoc, forward_assoc);
+
+ REGISTER_SPL_INTERFACE(spl, array_read);
+ REGISTER_SPL_INTF_FUNC(spl, array_read, get);
+ REGISTER_SPL_INTF_FUNC(spl, array_read, exists);
+
+ REGISTER_SPL_INTERFACE(spl, array_access);
+ REGISTER_SPL_PARENT_CE(spl, array_access, array_read);
+ REGISTER_SPL_INTF_FUNC(spl, array_access, set);
+
+ REGISTER_SPL_INTERFACE(spl, array_access_ex);
+ REGISTER_SPL_PARENT_CE(spl, array_access_ex, array_access);
+ REGISTER_SPL_INTF_FUNC(spl, array_access_ex, new_writer);
+
+ REGISTER_SPL_INTERFACE(spl, array_writer);
+ REGISTER_SPL_INTF_FUNC(spl, array_writer, set);
+
+#ifdef SPL_ARRAY_WRITE
+ REGISTER_SPL_STD_CLASS(spl, array_writer_default, spl_array_writer_default_create);
+ REGISTER_SPL_FUNCTIONS(spl, array_writer_default, spl_array_writer_funcs);
+#endif
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RINIT_FUNCTION(spl)
+ */
+PHP_RINIT_FUNCTION(spl)
+{
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RSHUTDOWN_FUNCTION(spl)
+ */
+PHP_RSHUTDOWN_FUNCTION(spl)
+{
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION(spl)
+ */
+PHP_MSHUTDOWN_FUNCTION(spl)
+{
+ SPL_DEBUG(fprintf(stderr, "%s\n", "Shutting down SPL");)
+
+#ifdef SPL_FOREACH
+ ZEND_EXECUTE_HOOK_RESTORE(ZEND_FE_RESET);
+ ZEND_EXECUTE_HOOK_RESTORE(ZEND_FE_FETCH);
+#endif
+
+#if defined(SPL_ARRAY_READ) | defined(SPL_ARRAY_WRITE)
+ ZEND_EXECUTE_HOOK_RESTORE(ZEND_FETCH_DIM_R);
+ ZEND_EXECUTE_HOOK_RESTORE(ZEND_FETCH_DIM_W);
+ ZEND_EXECUTE_HOOK_RESTORE(ZEND_FETCH_DIM_RW);
+#endif
+
+#ifdef SPL_ARRAY_WRITE
+ ZEND_EXECUTE_HOOK_RESTORE(ZEND_ASSIGN);
+#endif /* SPL_ARRAY_WRITE */
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO(spl)
+ */
+PHP_MINFO_FUNCTION(spl)
+{
+#ifdef SPL_FOREACH
+ char *foreach = "beta";
+#else /* SPL_ARRAY_WRITE */
+ char *foreach = "beta, not hooked";
+#endif
+#ifdef SPL_ARRAY_READ
+ char *array_read = "beta";
+#else /* SPL_ARRAY_WRITE */
+ char *array_read = "beta, not hooked";
+#endif
+#ifdef SPL_ARRAY_WRITE
+ char *array_write = "beta";
+#else /* SPL_ARRAY_WRITE */
+ char *array_write = "beta, not hooked";
+#endif /* SPL_ARRAY_WRITE */
+
+ php_info_print_table_start();
+ php_info_print_table_header(2, "SPL support", "enabled");
+ php_info_print_table_row(2, "iterator", foreach);
+ 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, "array_access_ex", array_write);
+ php_info_print_table_row(2, "array_writer", array_write);
+ php_info_print_table_end();
+}
+/* }}} */
+
+/* {{{ proto string class_name(object)
+ Retrieve */
+PHP_FUNCTION(class_name)
+{
+ zval *obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ RETURN_FALSE;
+ }
+ RETURN_STRING(spl_make_fully_qualyfied_name(Z_OBJCE_P(obj) TSRMLS_CC), 0);
+}
+/* }}} */
+
+/* {{{ class_parents
+ */
+PHP_FUNCTION(class_parents)
+{
+ zval *obj;
+ zend_class_entry *parent_class;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ RETURN_FALSE;
+ }
+ array_init(return_value);
+ parent_class = Z_OBJCE_P(obj)->parent;
+ while (parent_class) {
+ spl_add_class_name(return_value, parent_class TSRMLS_CC);
+ parent_class = parent_class->parent;
+ }
+}
+/* }}} */
+
+/* {{{ class_implements
+ */
+PHP_FUNCTION(class_implements)
+{
+ zval *obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ RETURN_FALSE;
+ }
+ array_init(return_value);
+ spl_add_interfaces(return_value, Z_OBJCE_P(obj) TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_classes */
+PHP_FUNCTION(spl_classes)
+{
+ array_init(return_value);
+ zend_hash_apply_with_argument(&spl_ns_spl->class_table, (apply_func_arg_t)spl_add_classes, return_value TSRMLS_CC);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/php_spl.h b/ext/spl/php_spl.h
new file mode 100755
index 0000000000..137e451cd5
--- /dev/null
+++ b/ext/spl/php_spl.h
@@ -0,0 +1,114 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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 PHP_SPL_H
+#define PHP_SPL_H
+
+#include "php.h"
+#include <stdarg.h>
+
+#if 0
+#define SPL_DEBUG(x) x
+#else
+#define SPL_DEBUG(x)
+#endif
+
+extern zend_module_entry spl_module_entry;
+#define phpext_spl_ptr &spl_module_entry
+
+#if defined(PHP_WIN32) && !defined(COMPILE_DL_SPL)
+#undef phpext_spl
+#define phpext_spl NULL
+#endif
+
+PHP_MINIT_FUNCTION(spl);
+PHP_MSHUTDOWN_FUNCTION(spl);
+PHP_RINIT_FUNCTION(spl);
+PHP_RSHUTDOWN_FUNCTION(spl);
+PHP_MINFO_FUNCTION(spl);
+
+#define ZEND_EXECUTE_HOOK_PTR(name) \
+ opcode_handler_t handler_ ## name
+
+#define ZEND_EXECUTE_HOOK(name) \
+ spl_globals->handler_ ## name = zend_opcode_handlers[name]; \
+ zend_opcode_handlers[name] = spl_handler_ ## name
+
+#define ZEND_EXECUTE_HOOK_RESTORE(name) \
+ zend_opcode_handlers[name] = SPL_G(handler_ ## name)
+
+#define ZEND_EXECUTE_HOOK_ORIGINAL(name) \
+ return SPL_G(handler_ ## name)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)
+
+#define ZEND_EXECUTE_HOOK_FUNCTION(name) \
+ int spl_handler_ ## name(ZEND_OPCODE_HANDLER_ARGS)
+
+
+ZEND_BEGIN_MODULE_GLOBALS(spl)
+#ifdef SPL_FOREACH
+ ZEND_EXECUTE_HOOK_PTR(ZEND_FE_RESET);
+ ZEND_EXECUTE_HOOK_PTR(ZEND_FE_FETCH);
+#endif
+#if defined(SPL_ARRAY_READ) | defined(SPL_ARRAY_WRITE)
+ ZEND_EXECUTE_HOOK_PTR(ZEND_FETCH_DIM_R);
+ ZEND_EXECUTE_HOOK_PTR(ZEND_FETCH_DIM_W);
+ ZEND_EXECUTE_HOOK_PTR(ZEND_FETCH_DIM_RW);
+#endif
+#ifdef SPL_ARRAY_WRITE
+ ZEND_EXECUTE_HOOK_PTR(ZEND_ASSIGN);
+#endif
+ZEND_END_MODULE_GLOBALS(spl)
+
+#ifdef ZTS
+# define SPL_G(v) TSRMG(spl_globals_id, zend_spl_globals *, v)
+extern int spl_globals_id;
+#else
+# define SPL_G(v) (spl_globals.v)
+extern zend_spl_globals spl_globals;
+#endif
+
+extern zend_namespace *spl_ns_spl;
+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;
+extern zend_class_entry *spl_ce_array_access_ex;
+extern zend_class_entry *spl_ce_array_writer;
+#ifdef SPL_ARRAY_WRITE
+extern zend_class_entry *spl_ce_array_writer_default;
+#endif /* SPL_ARRAY_WRITE */
+
+PHP_FUNCTION(spl_classes);
+PHP_FUNCTION(class_name);
+PHP_FUNCTION(class_parents);
+PHP_FUNCTION(class_implements);
+
+#endif /* PHP_SPL_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl.php b/ext/spl/spl.php
new file mode 100755
index 0000000000..ee92c0503c
--- /dev/null
+++ b/ext/spl/spl.php
@@ -0,0 +1,306 @@
+<?php
+
+/* \brief Standard PHP Library
+ *
+ * (c) M.Boerger 2003
+ */
+namespace spl {
+
+ /*! \brief Interface to foreach() construct
+ *
+ * Any class that implements this interface can for example be used as
+ * the input parameter to foreach() calls which would normally be an
+ * array.
+ *
+ * The only thing a class has to do is
+ */
+ interface iterator {
+
+ /*! \brief Create a new iterator
+ *
+ * used for example in foreach() operator.
+ */
+ function new_iterator();
+ }
+
+ /*! \brief Simple forward iterator
+ *
+ * Any class that implements this interface can be used as the
+ * return of a foreach interface. And hence the class itself
+ * can be used as a parameter to be iterated (normally an array).
+ *
+ * \code
+ class c implements spl::foreach, spl::forward {
+ private $num = 0;
+ function new_iterator() {
+ $this->num = 0;
+ return $this;
+ }
+ function current() {
+ return $this->num;
+ }
+ function next() {
+ $this->num++;
+ }
+ function has_more() {
+ return $this->num < 5;
+ }
+ }
+
+ $t = new c();
+
+ foreach($t as $num) {
+ echo "$num\n";
+ }
+ \endcode
+ *
+ * A very interesting usage scenario are for example database queries.
+ * Without this interface you need to do it without foreach or fetch the
+ * whole rowset into an array.
+ *
+ * In the above code the class implements both the foreach and the
+ * forward interface. Doing this you cannot have nested foreach calls.
+ * If you need this you must split the two parts.
+ *
+ * \code
+ class c implements spl::foreach {
+ public $max = 3;
+ function new_iterator() {
+ return new c_iter($this);
+ }
+ }
+ class c_iter implements spl::forward {
+ private $obj;
+ private $num = 0;
+ function __construct($obj) {
+ $this->obj = $obj;
+ }
+ function current() {
+ return $this->num;
+ }
+ function next() {
+ $this->num++;
+ }
+ function has_more() {
+ return $this->num < $this->obj->max;
+ }
+ }
+
+ $t = new c();
+
+ foreach($t as $outer) {
+ foreach($t as $inner) {
+ echo "$outer,$inner\n";
+ }
+ }
+ \endcode
+ *
+ * You can also use this interface with the for() construct.
+ *
+ * \code
+ class c implements spl::foreach {
+ public $max = 3;
+ function new_iterator() {
+ return new c_iter($this);
+ }
+ }
+ class c_iter implements spl::forward {
+ private $obj;
+ private $num = 0;
+ function __construct($obj) {
+ $this->obj = $obj;
+ }
+ function current() {
+ return $this->num;
+ }
+ function next() {
+ $this->num++;
+ }
+ function has_more() {
+ return $this->num < $this->obj->max;
+ }
+ }
+
+ $t = new c();
+
+ for ($iter = $t->new_iterator(); $iter->has_more(); $iter->next()) {
+ echo $iter->current() . "\n";
+ }
+ \endcode
+ */
+ interface forward {
+
+ /*! \brief Retrieve the current currentent
+ *
+ * \return \c mixed current element or \c false if no more elements
+ */
+ function current();
+
+ /*! \brief Forward to next element.
+ */
+ function next();
+
+ /*! \brief Check if more elements are available.
+ *
+ * \return \c bool whether or not more elements are available
+ */
+ function has_more();
+ }
+
+ /*! \brief A restartable iterator.
+ *
+ * This iterator allows you to implement a restartable iterator. That
+ * means the iterator can be rewind to the first element after accessing
+ * any number of elements.
+ *
+ * \note If you use sequence in foreach then rewind() will be called
+ * first.
+ */
+ interface sequence extends forward {
+
+ /*! Restart the sequence by positioning it to the first element.
+ */
+ function rewind();
+ }
+
+ /*! \brief associative interface
+ *
+ * This interface allows to implement associative iterators
+ * and containers.
+ */
+ interface assoc {
+
+ /*! \brief Retrieve the current elements key
+ *
+ * \return \c mixed current key or \c false if no more elements
+ */
+ function key();
+ }
+
+ /*! \brief associative foreach() interface
+ *
+ * This interface extends the forward interface to support keys.
+ * With this interface you can do:
+ * \code
+ $t = new c();
+ foreach($t as $key => $elem).
+ \endcode
+ */
+ interface assoc_forward extends forward implements assoc {
+ }
+
+ /*! \brief associative sequence
+ */
+ interface assoc_sequence extends sequence implements assoc {
+ }
+
+ /*! \brief array read only access for objects
+ */
+ interface array_read {
+
+ /*! Check whether or not the given index exists.
+ * The returned value is interpreted as converted to bool.
+ */
+ function exists($index);
+
+ /*! Read the value at position $index.
+ * This function is only beeing called if exists() returns true.
+ */
+ function get($index);
+ }
+
+ /*! \brief array read/write access for objects.
+ *
+ * The following example shows how to use an array_writer:
+ * \code
+ class array_emulation implemets spl::array_access {
+ private $ar = array();
+ function exists($index) {
+ return array_key_exists($index, $this->ar);
+ }
+ function get($index) {
+ return $this->ar[$index];
+ }
+ function set($index, $value) {
+ $this->ar[$index] = $value;
+ }
+ }
+ \endcode
+ */
+ interface array_access extends array_read {
+
+ /*! Set the value identified by $index to $value.
+ */
+ function set($value, $index);
+ }
+
+ /*! \brief array read/write access with customized array_writer
+ *
+ * The internal structure requires that write access via interfaces
+ * is divided into two parts. First the index is used to create an
+ * array_writer which will later receive the new value and calls the
+ * containers set() method with appropriate parameters.
+ *
+ * Sometimes it is helpfull to overwrite this behavior and have your
+ * own implementation for the array_writer.
+ *
+ * The following example shows how to use a customized array_writer:
+ * \code
+ class array_emulation_ex extends array_emulation implemets spl::array_access_ex {
+ private $last_index = NULL;
+ function new_writer($index) {
+ $last_index = $index;
+ return new array_write(&$this, $index);
+ }
+ }
+ \endcode
+ */
+ interface array_access_ex extends array_access {
+
+ /*! Create an array_writer interface for the specified index.
+ *
+ * If your container uses array_access instead of array_access_ex
+ * the following code would be equal to the internal new_writer()
+ * method:
+ \code
+ function new_writer($index) {
+ return new array_write(&$this, $index);
+ }
+ \endcode
+ */
+ function new_writer($index);
+ }
+
+ /*! \brief array writer interface
+ *
+ * for every write access to an array_access instance an array_writer
+ * is created which receives the originating object and the index as
+ * parameters for the constructor call.
+ *
+ * The following shows the equivalent php code for the default
+ * implementation array_write.
+ * \code
+ class array_write implements array_writer {
+ private $obj;
+ private $idx;
+ function __construct(&$obj, $index = null) {
+ $this->obj = $obj;
+ $this->idx = $index;
+ }
+ function set($value) {
+ return $this->obj->set($this->idx, $value);
+ }
+ }
+ \endcode
+ *
+ * See array_access for more.
+ */
+ interface array_writer {
+
+ /*! Set the corresponding value to $value.
+ */
+ function set($value);
+ }
+
+}
+?> \ No newline at end of file
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
new file mode 100755
index 0000000000..7c68d3c06f
--- /dev/null
+++ b/ext/spl/spl_array.c
@@ -0,0 +1,349 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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 "zend_execute_locks.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_array_writer_default stuff */
+typedef struct {
+ zval *obj;
+ zval *idx;
+} spl_array_writer_object;
+
+static zend_class_entry *spl_array_writer_default_get_class(zval *object TSRMLS_DC)
+{
+#ifdef SPL_ARRAY_WRITE
+ return spl_ce_array_writer_default;
+#else
+ return (zend_class_entry *)1; /* force an error here: this ensures not equal */
+#endif
+}
+
+static zend_object_handlers spl_array_writer_default_handlers = {
+ ZEND_OBJECTS_STORE_HANDLERS,
+
+ NULL, /* read_property */
+ NULL, /* write_property */
+ NULL, /* get_property_ptr */
+ NULL, /* get_property_zval_ptr */
+ NULL, /* get */
+ NULL, /* set */
+ NULL, /* has_property */
+ NULL, /* unset_property */
+ NULL, /* get_properties */
+ NULL, /* get_method */
+ NULL, /* call_method */
+ NULL, /* get_constructor */
+ spl_array_writer_default_get_class, /* get_class_entry */
+ NULL, /* get_class_name */
+ NULL /* compare_objects */
+};
+/* }}} */
+
+/* {{{ spl_array_writer_dtor */
+void spl_array_writer_default_dtor(void *object, zend_object_handle handle TSRMLS_DC)
+{
+ spl_array_writer_object *writer = (spl_array_writer_object*) object;
+
+ if (writer->obj)
+ {
+ writer->obj->refcount--;
+/* DELETE_ZVAL(writer->obj); */
+ }
+ if (writer->idx)
+ {
+ writer->idx->refcount--;
+ DELETE_ZVAL(writer->idx);
+ }
+ efree(writer);
+}
+/* }}} */
+
+/* {{{ spl_array_writer_default_create */
+zend_object_value spl_array_writer_default_create(zend_class_entry *class_type TSRMLS_DC)
+{
+ zend_object_value retval;
+ spl_array_writer_object *intern;
+
+ intern = ecalloc(sizeof(spl_array_writer_object), 1);
+
+ retval.handle = zend_objects_store_put(intern, spl_array_writer_default_dtor, NULL TSRMLS_CC);
+ retval.handlers = &spl_array_writer_default_handlers;
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ spl_array_writer_default_set */
+void spl_array_writer_default_set(zval *object, zval *newval, zval **retval TSRMLS_DC)
+{
+ zval *obj, *idx;
+ spl_array_writer_object *writer;
+
+ writer = (spl_array_writer_object *) zend_object_store_get_object(object TSRMLS_CC);
+ obj = writer->obj;
+ idx = writer->idx;
+ spl_begin_method_call_arg_ex2(&obj, "set", retval, &idx, &newval, 0, NULL TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ SPL_CLASS_FUNCTION(array_writer_default, __construct) */
+SPL_CLASS_FUNCTION(array_writer_default, __construct)
+{
+ zval *object = getThis();
+ zval *obj, *idx;
+ spl_array_writer_object *writer;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &obj, &idx) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to parse parameters");
+ return;
+ }
+ writer = (spl_array_writer_object *) zend_object_store_get_object(object TSRMLS_CC);
+ writer->obj = obj; obj->refcount++;
+ writer->idx = idx; idx->refcount++;
+
+}
+/* }}} */
+
+/* {{{ SPL_CLASS_FUNCTION(array_writer_default, set) */
+SPL_CLASS_FUNCTION(array_writer_default, set)
+{
+ zval *object = getThis();
+ zval *newval;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &newval) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to parse parameters");
+ return;
+ }
+ spl_array_writer_default_set(object, newval, &return_value TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_fetch_dimension_address */
+int spl_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
+{
+ zval **container_ptr = spl_get_zval_ptr_ptr(op1, Ts TSRMLS_CC);
+
+ if (spl_is_instance_of(container_ptr, spl_ce_array_read TSRMLS_CC)) {
+ zval **retval = &(T(result->u.var).var.ptr);
+ zval *dim = spl_get_zval_ptr(op2, Ts, &EG(free_op2) TSRMLS_CC);
+ zval *exists;
+
+ /*ALLOC_ZVAL(exists); not needed */
+ spl_begin_method_call_arg_ex1(container_ptr, "exists", &exists, &dim, 0, NULL TSRMLS_CC);
+ 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_begin_method_call_arg_ex1(container_ptr, "get", retval, &dim, 0, NULL TSRMLS_CC);
+ (*retval)->refcount--;
+ } else
+#ifdef SPL_ARRAY_WRITE
+ if (spl_is_instance_of(container_ptr, spl_ce_array_access_ex TSRMLS_CC)) {
+ /* array_access_ex instaces have their own way of creating an access_writer */
+ spl_begin_method_call_arg_ex1(container_ptr, "new_writer", retval, &dim, 0, NULL TSRMLS_CC);
+ T(result->u.var).var.ptr = *retval;
+ AI_PTR_2_PTR_PTR(T(result->u.var).var);
+ SELECTIVE_PZVAL_LOCK(*retval, result);
+ } else if (spl_is_instance_of(container_ptr, spl_ce_array_access TSRMLS_CC)) {
+ /* array_access instances create the default array_writer: array_write */
+ spl_array_writer_object *writer;
+ spl_instanciate(spl_ce_array_writer_default, retval TSRMLS_CC);
+ T(result->u.var).var.ptr = *retval;
+ AI_PTR_2_PTR_PTR(T(result->u.var).var);
+ writer = (spl_array_writer_object *) zend_object_store_get_object(*retval TSRMLS_CC);
+ writer->obj = *container_ptr; writer->obj->refcount++;
+ writer->idx = dim; writer->idx->refcount++;
+ SELECTIVE_PZVAL_LOCK(*retval, result);
+ } else {
+ zend_error(E_ERROR, "Object must implement spl::array_access for write access");
+ retval = &EG(error_zval_ptr);
+ }
+ SELECTIVE_PZVAL_LOCK(*retval, result);
+#else
+ zend_error(E_ERROR, "SPL compiled withut array write hook");
+#endif
+ 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) {
+ PZVAL_LOCK(*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
+/* }}} */
+
+/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN) */
+#ifdef SPL_ARRAY_WRITE
+ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN)
+{
+ zval **writer = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+ zval *newval, *retval, *target;
+ znode *result;
+
+ if (writer && *writer && Z_TYPE_PP(writer) == IS_OBJECT) {
+ /* optimization: do pre checks and only test for handlers in case of
+ * spl::array_writer_default, for spl::array_writer we must use the
+ * long way of calling spl_instance
+ * if (spl_is_instance_of(writer, spl_ce_array_writer_default TSRMLS_CC))
+ */
+ if ((*writer)->value.obj.handlers == &spl_array_writer_default_handlers) {
+ newval = spl_get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2) TSRMLS_CC);
+ spl_array_writer_default_set(*writer, newval, &retval TSRMLS_CC);
+ } else if (spl_is_instance_of(writer, spl_ce_array_writer TSRMLS_CC)) {
+ newval = spl_get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2) TSRMLS_CC);
+ spl_begin_method_call_arg_ex1(writer, "set", &retval, &newval, 0, NULL TSRMLS_CC);
+ } else {
+ ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN);
+ }
+ } else {
+ ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN);
+ }
+ spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+
+ result = &EX(opline)->result;
+ if (result) {
+ if (retval->refcount<2) {
+ if ((*writer)->value.obj.handlers == &spl_array_writer_default_handlers) {
+ spl_array_writer_object *object = (spl_array_writer_object *) zend_object_store_get_object(*writer TSRMLS_CC);
+ target = object->obj;
+ } else {
+ target = *writer;
+ }
+ zend_error(E_WARNING, "Method %s::set() did not return a value, using NULL", Z_OBJCE_P(target)->name);
+ DELETE_ZVAL(retval);
+ DELETE_ZVAL(newval);
+ /* Unfortunately it doesn't work when trying to return newval.
+ * But anyhow it wouldn't make sense...and confuse reference counting and such.
+ */
+ retval = &EG(uninitialized_zval);
+ } else {
+ retval->refcount--;
+ }
+ EX_T(EX(opline)->result.u.var).var.ptr = retval;
+ AI_PTR_2_PTR_PTR(EX_T(EX(opline)->result.u.var).var);
+ SELECTIVE_PZVAL_LOCK(retval, result);
+ } else {
+ retval->refcount = 1;
+ DELETE_ZVAL(retval);
+ }
+
+ (*writer)->refcount = 1;
+ DELETE_ZVAL(*writer);
+ FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2));
+
+ NEXT_OPCODE();
+}
+#endif
+/* }}} */
+
+/*
+ * 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_array.h b/ext/spl/spl_array.h
new file mode 100755
index 0000000000..7f27f5dce1
--- /dev/null
+++ b/ext/spl/spl_array.h
@@ -0,0 +1,49 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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_ARRAY_H
+#define SPL_ARRAY_H
+
+#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
+
+#ifdef SPL_ARRAY_WRITE
+ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN);
+#endif
+
+SPL_CLASS_FUNCTION(array_writer_default, __construct);
+SPL_CLASS_FUNCTION(array_writer_default, set);
+
+zend_object_value spl_array_writer_default_create(zend_class_entry *class_type TSRMLS_DC);
+
+#endif /* SPL_ARRAY_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_engine.c b/ext/spl/spl_engine.c
new file mode 100755
index 0000000000..84e5d8aca3
--- /dev/null
+++ b/ext/spl/spl_engine.c
@@ -0,0 +1,223 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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 "zend_execute_locks.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+
+/* {{{ spl_begin_method_call_arg */
+int spl_begin_method_call_arg(zval **ce, char *function_name, zval *retval, zval *arg1 TSRMLS_DC)
+{
+ zval *args[1];
+ zval fn_name;
+
+ ZVAL_STRING(&fn_name, function_name, 0);
+
+ args[0] = arg1;
+ return call_user_function(&Z_OBJCE_PP(ce)->function_table, ce, &fn_name, retval, 1, args TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_begin_method_call_this */
+int spl_begin_method_call_this(zval **ce, char *function_name, zval *retval TSRMLS_DC)
+{
+ zval fn_name;
+
+ ZVAL_STRING(&fn_name, function_name, 0);
+
+ return call_user_function(&Z_OBJCE_PP(ce)->function_table, ce, &fn_name, retval, 0, NULL TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_begin_method_call_arg_ex1 */
+int spl_begin_method_call_arg_ex1(zval **ce, char *function_name, zval **retval, zval **arg1, int no_separation, HashTable *symbol_table TSRMLS_DC)
+{
+ zval **args[1];
+ zval fn_name;
+
+ ZVAL_STRING(&fn_name, function_name, 0);
+
+ args[0] = arg1;
+ return call_user_function_ex(&Z_OBJCE_PP(ce)->function_table, ce, &fn_name, retval, 1, args, no_separation, symbol_table TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_begin_method_call_arg_ex2 */
+int spl_begin_method_call_arg_ex2(zval **ce, char *function_name, zval **retval, zval **arg1, zval **arg2, int no_separation, HashTable *symbol_table TSRMLS_DC)
+{
+ zval **args[2];
+ zval fn_name;
+
+ ZVAL_STRING(&fn_name, function_name, 0);
+
+ args[0] = arg1;
+ args[1] = arg2;
+ return call_user_function_ex(&Z_OBJCE_PP(ce)->function_table, ce, &fn_name, retval, 2, args, no_separation, symbol_table TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_instanciate */
+void spl_instanciate(zend_class_entry *pce, zval **object TSRMLS_DC)
+{
+ 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, int no_separation, HashTable *symbol_table TSRMLS_DC)
+{
+ zval **args[2];
+ zval fn_name;
+ zval *object;
+
+ spl_instanciate(pce, &object TSRMLS_CC);
+
+ retval = &EG(uninitialized_zval_ptr);
+
+ ZVAL_STRING(&fn_name, pce->constructor->common.function_name, 0);
+
+ args[0] = arg1;
+ args[1] = arg2;
+ call_user_function_ex(&pce->function_table, &object, &fn_name, retval, 2, args, no_separation, symbol_table 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) {
+ PZVAL_UNLOCK(*T(node->u.var).var.ptr_ptr);
+ } else if (T(node->u.var).EA.type==IS_STRING_OFFSET) {
+ PZVAL_UNLOCK(T(node->u.var).EA.data.str_offset.str);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ spl_get_zval_ptr */
+zval * spl_get_zval_ptr(znode *node, temp_variable *Ts, zval **should_free 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) {
+ PZVAL_UNLOCK(T(node->u.var).var.ptr);
+ *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;
+ }
+ PZVAL_UNLOCK(str);
+ 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()
+ }
+ return NULL;
+}
+/* }}} */
+
+/* {{{ spl_is_instance_of */
+int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC)
+{
+ /* Ensure everything needed is available before checking for the type.
+ * HAS_CLASS_ENTRY is neededto ensure Z_OBJCE_PP will not throw an error.
+ */
+ if (!obj || !*obj || Z_TYPE_PP(obj) != IS_OBJECT || !HAS_CLASS_ENTRY(**obj)) {
+ return 0;
+ } else {
+ zend_class_entry *instance_ce = Z_OBJCE_PP(obj);
+
+ if (instanceof_function(instance_ce, ce TSRMLS_CC)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+/* }}} */
+
+/*
+ * 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_engine.h b/ext/spl/spl_engine.h
new file mode 100755
index 0000000000..ded59f4412
--- /dev/null
+++ b/ext/spl/spl_engine.h
@@ -0,0 +1,63 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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_ENGINE_H
+#define SPL_ENGINE_H
+
+#include "php.h"
+#include "php_spl.h"
+
+#include "zend_compile.h"
+#include "zend_execute_locks.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;
+
+int zend_do_fcall_common_helper(ZEND_OPCODE_HANDLER_ARGS);
+
+int spl_begin_method_call_arg(zval **ce, char *function_name, zval *retval, zval *arg1 TSRMLS_DC);
+int spl_begin_method_call_this(zval **ce, char *function_name, zval *retval TSRMLS_DC);
+int spl_begin_method_call_arg_ex1(zval **ce, char *function_name, zval **retval, zval **arg1, int no_separation, HashTable *symbol_table TSRMLS_DC);
+int spl_begin_method_call_arg_ex2(zval **ce, char *function_name, zval **retval, zval **arg1, zval **arg2, int no_separation, HashTable *symbol_table TSRMLS_DC);
+
+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, int no_separation, HashTable *symbol_table 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);
+
+int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC);
+
+
+#endif /* SPL_ENGINE_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/spl_foreach.c b/ext/spl/spl_foreach.c
new file mode 100755
index 0000000000..8474639bcd
--- /dev/null
+++ b/ext/spl/spl_foreach.c
@@ -0,0 +1,130 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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 "zend_execute_locks.h"
+
+#include "php_spl.h"
+#include "spl_functions.h"
+#include "spl_engine.h"
+#include "spl_foreach.h"
+
+/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET) */
+ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET)
+{
+ zval **obj, *retval;
+
+ if (EX(opline)->extended_value) {
+ obj = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+ if (spl_is_instance_of(obj, spl_ce_iterator TSRMLS_CC)) {
+ spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+ MAKE_STD_ZVAL(retval);
+ spl_begin_method_call_this(obj, "new_iterator", retval TSRMLS_CC);
+ EX_T(EX(opline)->result.u.var).var.ptr = retval;
+ EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;
+ EX(opline)->op2.u.EA.type = 0; /* missuse as index */
+
+ PZVAL_LOCK(retval);
+
+ NEXT_OPCODE();
+ } else if (spl_is_instance_of(obj, spl_ce_forward TSRMLS_CC)) {
+ spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+
+ EX_T(EX(opline)->result.u.var).var.ptr = *obj;
+ EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;
+ EX(opline)->op2.u.EA.type = 0; /* missuse as index */
+
+ (*obj)->refcount++;
+ PZVAL_LOCK(*obj);
+
+ NEXT_OPCODE();
+ }
+ }
+ ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
+}
+/* }}} */
+
+/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH) */
+ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH)
+{
+ zval **obj = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+ zval more, tmp, *value, *key, *result;
+
+ if (spl_is_instance_of(obj, spl_ce_forward TSRMLS_CC)) {
+ zend_uint index = EX(opline)->op2.u.EA.type++;
+
+ spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
+ PZVAL_LOCK(*obj);
+
+ if (index) {
+ spl_begin_method_call_this(obj, "next", &more TSRMLS_CC);
+ } else if (spl_is_instance_of(obj, spl_ce_sequence TSRMLS_CC)) {
+ spl_begin_method_call_this(obj, "rewind", &more TSRMLS_CC);
+ }
+
+ spl_begin_method_call_this(obj, "has_more", &more TSRMLS_CC);
+ if (zend_is_true(&more)) {
+ result = &EX_T(EX(opline)->result.u.var).tmp_var;
+ array_init(result);
+ ALLOC_ZVAL(value);
+
+ spl_begin_method_call_this(obj, "current", value TSRMLS_CC);
+
+ zend_hash_index_update(result->value.ht, 0, &value, sizeof(zval *), NULL);
+
+ if (spl_is_instance_of(obj, spl_ce_assoc TSRMLS_CC)) {
+ ALLOC_ZVAL(key);
+ spl_begin_method_call_this(obj, "key", key TSRMLS_CC);
+ } else {
+ /* If someone makes a reference to this value then there is
+ * a real problem. And the only way to avoid it is to alloc
+ * dealloc this temporary zval then.
+ */
+ tmp.value.lval = index;
+ tmp.type = IS_LONG;
+ tmp.refcount = 0;
+ tmp.is_ref = 0;
+ key = &tmp;
+ }
+ zend_hash_index_update(result->value.ht, 1, &key, sizeof(zval *), NULL);
+
+ NEXT_OPCODE();
+ }
+ else
+ EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
+ return 0;
+ }
+ ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_FETCH);
+}
+/* }}} */
+
+/*
+ * 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_foreach.h b/ext/spl/spl_foreach.h
new file mode 100755
index 0000000000..427f331233
--- /dev/null
+++ b/ext/spl/spl_foreach.h
@@ -0,0 +1,37 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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_FOREACH_H
+#define SPL_FOREACH_H
+
+#include "php.h"
+#include "php_spl.h"
+
+ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET);
+ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH);
+
+#endif /* SPL_FOREACH_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 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
new file mode 100755
index 0000000000..1977db1ae9
--- /dev/null
+++ b/ext/spl/spl_functions.c
@@ -0,0 +1,187 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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 "php_spl.h"
+#include "spl_foreach.h"
+
+/* {{{ spl_destroy_class */
+void spl_destroy_class(zend_class_entry ** ppce)
+{
+ SPL_DEBUG(fprintf(stderr, "Destroy(%s): %s\n", (*ppce)->type == ZEND_USER_CLASS ? "user" : "other", (*ppce)->name);)
+ destroy_zend_class(ppce);
+}
+/* }}} */
+
+/* {{{ spl_register_namespace */
+void spl_register_namespace(zend_namespace ** ppns, char * namespace_name TSRMLS_DC)
+{
+ zend_namespace ns;
+
+ INIT_NAMESPACE(ns, namespace_name);
+ *ppns = zend_register_internal_namespace(&ns TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ spl_register_interface */
+void spl_register_interface(zend_class_entry ** ppce, zend_namespace * namespace_entry, char * class_name TSRMLS_DC)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, class_name, NULL);
+ ce.num_interfaces = 0;
+ *ppce = zend_register_internal_ns_class(&ce, NULL, namespace_entry, NULL TSRMLS_CC);
+
+ /* entries changed by initialize */
+ (*ppce)->ce_flags = ZEND_ACC_ABSTRACT | ZEND_ACC_INTERFACE;
+ (*ppce)->ns = namespace_entry;
+}
+/* }}} */
+
+/* {{{ spl_register_std_class */
+void spl_register_std_class(zend_class_entry ** ppce, zend_namespace * namespace_entry, char * class_name, void * obj_ctor TSRMLS_DC)
+{
+ zend_class_entry ce;
+ memset(&ce, 0, sizeof(zend_class_entry));
+
+ INIT_CLASS_ENTRY(ce, class_name, NULL);
+
+ ce.num_interfaces = 0;
+
+ *ppce = zend_register_internal_ns_class(&ce, NULL, namespace_entry, NULL TSRMLS_CC);
+
+ /* entries changed by initialize */
+ (*ppce)->ce_flags = ZEND_ACC_ABSTRACT | ZEND_ACC_INTERFACE;
+ (*ppce)->create_object = obj_ctor;
+ (*ppce)->ns = namespace_entry;
+}
+/* }}} */
+
+/* {{{ spl_register_interface_function */
+void spl_register_interface_function(zend_class_entry * class_entry, char * fn_name TSRMLS_DC)
+{
+ zend_function function, *reg_function;
+ zend_internal_function *pfunction = (zend_internal_function *)&function;
+
+ pfunction->type = ZEND_INTERNAL_FUNCTION;
+ pfunction->handler = NULL;
+ pfunction->arg_types = NULL;
+ pfunction->function_name = fn_name;
+ pfunction->scope = class_entry;
+ pfunction->fn_flags = ZEND_ACC_ABSTRACT | ZEND_ACC_PUBLIC;
+ pfunction->ns = class_entry->ns;
+ pfunction->prototype = NULL;
+ zend_hash_add(&class_entry->function_table, fn_name, strlen(fn_name)+1, &function, sizeof(zend_function), (void**)&reg_function);
+}
+/* }}} */
+
+/* {{{ spl_register_parent_ce */
+void spl_register_parent_ce(zend_class_entry * class_entry, zend_class_entry * parent_class TSRMLS_DC)
+{
+ class_entry->parent = parent_class;
+}
+/* }}} */
+
+/* {{{ spl_register_implement */
+void spl_register_implement(zend_class_entry * class_entry, zend_class_entry * interface_entry TSRMLS_DC)
+{
+ zend_uint num_interfaces = ++class_entry->num_interfaces;
+ class_entry->interfaces = (zend_class_entry **) realloc(class_entry->interfaces, sizeof(zend_class_entry *) * num_interfaces);
+ class_entry->interfaces[num_interfaces-1] = interface_entry;
+}
+/* }}} */
+
+/* {{{ spl_register_functions */
+void spl_register_functions(zend_class_entry * class_entry, function_entry * function_list TSRMLS_DC)
+{
+ zend_register_functions(class_entry, function_list, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
+}
+/* }}} */
+
+/* {{ spl_make_fully_qualyfied_name */
+char * spl_make_fully_qualyfied_name(zend_class_entry * pce TSRMLS_DC)
+{
+ if (pce->ns && (pce->ns != &CG(global_namespace))) {
+ char *retval;
+
+ spprintf(&retval, 0, "%s::%s", pce->ns->name, pce->name);
+ return retval;
+ } else {
+ return estrdup(pce->name);
+ }
+}
+/* }}} */
+
+/* {{{ spl_add_class_name */
+void spl_add_class_name(zval * list, zend_class_entry * pce TSRMLS_DC)
+{
+ char * str = spl_make_fully_qualyfied_name(pce TSRMLS_CC);
+ zval *tmp;
+
+ if (zend_hash_find(Z_ARRVAL_P(list), str, strlen(str)+1, (void*)&tmp) == FAILURE) {
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRING(tmp, str, 0);
+ zend_hash_add(Z_ARRVAL_P(list), str, strlen(str)+1, &tmp, sizeof(zval *), NULL);
+ } else {
+ efree(str);
+ }
+}
+/* }}} */
+
+/* {{{ spl_add_interfaces */
+void spl_add_interfaces(zval *list, zend_class_entry * pce TSRMLS_DC)
+{
+ zend_uint num_interfaces;
+
+ for (num_interfaces = 0; num_interfaces < pce->num_interfaces; num_interfaces++) {
+ spl_add_class_name(list, pce->interfaces[num_interfaces] TSRMLS_CC);
+ spl_add_interfaces(list, pce->interfaces[num_interfaces] TSRMLS_CC);
+ }
+ if (pce->parent) {
+ spl_add_class_name(list, pce->parent TSRMLS_CC);
+ spl_add_interfaces(list, pce->parent TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ spl_add_interfaces */
+int spl_add_classes(zend_class_entry ** ppce, zval *list TSRMLS_DC)
+{
+ spl_add_class_name(list, *ppce TSRMLS_CC);
+ if ((*ppce)->parent) {
+ spl_add_classes(&(*ppce)->parent, list TSRMLS_CC);
+ }
+ spl_add_interfaces(list, *ppce TSRMLS_CC);
+ return 0;
+}
+/* }}} */
+
+/*
+ * 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.h b/ext/spl/spl_functions.h
new file mode 100755
index 0000000000..f6a7b57ab4
--- /dev/null
+++ b/ext/spl/spl_functions.h
@@ -0,0 +1,80 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.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 PHP_FUNCTIONS_H
+#define PHP_FUNCTIONS_H
+
+#include "php.h"
+
+typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type TSRMLS_DC);
+
+#define REGISTER_SPL_NAMESPACE(namespace_name) \
+ spl_register_namespace(&spl_ns_ ## namespace_name, # namespace_name TSRMLS_CC);
+
+#define REGISTER_SPL_STD_CLASS(namespace_name, class_name, obj_ctor) \
+ spl_register_std_class(&spl_ce_ ## class_name, spl_ns_ ## namespace_name, # class_name, obj_ctor TSRMLS_CC);
+
+#define REGISTER_SPL_INTERFACE(namespace_name, class_name) \
+ spl_register_interface(&spl_ce_ ## class_name, spl_ns_ ## namespace_name, # class_name TSRMLS_CC);
+
+#define REGISTER_SPL_INTF_FUNC(namespace_name, class_name, function_name) \
+ spl_register_interface_function(spl_ce_ ## class_name, # function_name TSRMLS_CC);
+
+#define REGISTER_SPL_PARENT_CE(namespace_name, class_name, parent_class) \
+ spl_register_parent_ce(spl_ce_ ## class_name, spl_ce_ ## parent_class TSRMLS_CC);
+
+#define REGISTER_SPL_IMPLEMENT(namespace_name, class_name, interface_name) \
+ spl_register_implement(spl_ce_ ## class_name, spl_ce_ ## interface_name TSRMLS_CC);
+
+#define REGISTER_SPL_FUNCTIONS(namespace_name, class_name, function_list) \
+ spl_register_functions(spl_ce_ ## class_name, function_list TSRMLS_CC);
+
+void spl_destroy_class(zend_class_entry ** ppce);
+
+void spl_register_namespace(zend_namespace ** ppns, char * namespace_name TSRMLS_DC);
+
+void spl_register_std_class(zend_class_entry ** ppce, zend_namespace * namespace_entry, char * class_name, create_object_func_t ctor TSRMLS_DC);
+
+void spl_register_interface(zend_class_entry ** ppce, zend_namespace * namespace_entry, char * class_name TSRMLS_DC);
+
+void spl_register_interface_function(zend_class_entry * class_entry, char * fn_name 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);
+
+char * spl_make_fully_qualyfied_name(zend_class_entry * pce TSRMLS_DC);
+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_types) \
+ PHP_NAMED_FE( function_name, spl_ ## class_name ## function_name, arg_types)
+
+#define SPL_CLASS_FUNCTION(class_name, function_name) \
+ PHP_NAMED_FUNCTION(spl_ ## class_name ## function_name)
+
+#endif /* PHP_FUNCTIONS_H */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/ext/spl/tests/.htaccess b/ext/spl/tests/.htaccess
new file mode 100755
index 0000000000..5a01a1c16e
--- /dev/null
+++ b/ext/spl/tests/.htaccess
@@ -0,0 +1,3 @@
+<IfModule mod_autoindex.c>
+ IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t *.php
+</IfModule>
diff --git a/ext/spl/tests/array_access_001.phpt b/ext/spl/tests/array_access_001.phpt
new file mode 100755
index 0000000000..5748a5c594
--- /dev/null
+++ b/ext/spl/tests/array_access_001.phpt
@@ -0,0 +1,127 @@
+--TEST--
+SPL: array_access
+--SKIPIF--
+<?php
+ if (!extension_loaded("spl")) die("skip");
+ if (!in_array("spl::array_access",spl_classes())) die("skip spl::array_access not present");
+?>
+--FILE--
+<?php
+class c implements spl::array_access {
+
+ public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+ function exists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $this->a);
+ }
+ function get($index) {
+ echo __METHOD__ . "($index)\n";
+ return $this->a[$index];
+ }
+ function set($index, $newval) {
+ echo __METHOD__ . "($index,$newval)\n";
+ return $this->a[$index] = $newval;
+ }
+}
+
+$obj = new c();
+
+var_dump($obj->a);
+
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+echo "WRITE 1\n";
+$obj[1] = 'Changed 1';
+var_dump($obj[1]);
+echo "WRITE 2\n";
+$obj['4th'] = 'Changed 4th';
+var_dump($obj['4th']);
+echo "WRITE 3\n";
+$obj['5th'] = 'Added 5th';
+var_dump($obj['5th']);
+echo "WRITE 4\n";
+$obj[6] = 'Added 6';
+var_dump($obj[6]);
+
+var_dump($obj[0]);
+var_dump($obj[2]);
+
+$x = $obj[6] = 'changed 6';
+var_dump($obj[6]);
+var_dump($x);
+
+print "Done\n";
+?>
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ int(1)
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ int(4)
+}
+c::exists(0)
+c::get(0)
+string(3) "1st"
+c::exists(1)
+c::get(1)
+int(1)
+c::exists(2)
+c::get(2)
+string(3) "3rd"
+c::exists(4th)
+c::get(4th)
+int(4)
+c::exists(5th)
+
+Notice: Undefined index: 5th in %s on line %d
+NULL
+c::exists(6)
+
+Notice: Undefined index: 6 in %s on line %d
+NULL
+WRITE 1
+c::exists(1)
+c::set(1,Changed 1)
+c::exists(1)
+c::get(1)
+string(9) "Changed 1"
+WRITE 2
+c::exists(4th)
+c::set(4th,Changed 4th)
+c::exists(4th)
+c::get(4th)
+string(11) "Changed 4th"
+WRITE 3
+c::exists(5th)
+c::set(5th,Added 5th)
+c::exists(5th)
+c::get(5th)
+string(9) "Added 5th"
+WRITE 4
+c::exists(6)
+c::set(6,Added 6)
+c::exists(6)
+c::get(6)
+string(7) "Added 6"
+c::exists(0)
+c::get(0)
+string(3) "1st"
+c::exists(2)
+c::get(2)
+string(3) "3rd"
+c::exists(6)
+c::set(6,changed 6)
+c::exists(6)
+c::get(6)
+string(9) "changed 6"
+string(9) "changed 6"
+Done
diff --git a/ext/spl/tests/array_access_002.phpt b/ext/spl/tests/array_access_002.phpt
new file mode 100755
index 0000000000..d415b19248
--- /dev/null
+++ b/ext/spl/tests/array_access_002.phpt
@@ -0,0 +1,137 @@
+--TEST--
+SPL: array_access without return in set()
+--SKIPIF--
+<?php
+ if (!extension_loaded("spl")) die("skip");
+ if (!in_array("spl::array_access",spl_classes())) die("skip spl::array_access not present");
+?>
+--FILE--
+<?php
+class c implements spl::array_access {
+
+ public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+ function exists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $this->a);
+ }
+ function get($index) {
+ echo __METHOD__ . "($index)\n";
+ return $this->a[$index];
+ }
+ function set($index, $newval) {
+ echo __METHOD__ . "($index,$newval)\n";
+ /* return */ $this->a[$index] = $newval;
+ }
+}
+
+$obj = new c();
+
+var_dump($obj->a);
+
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+echo "WRITE 1\n";
+$obj[1] = 'Changed 1';
+var_dump($obj[1]);
+echo "WRITE 2\n";
+$obj['4th'] = 'Changed 4th';
+var_dump($obj['4th']);
+echo "WRITE 3\n";
+$obj['5th'] = 'Added 5th';
+var_dump($obj['5th']);
+echo "WRITE 4\n";
+$obj[6] = 'Added 6';
+var_dump($obj[6]);
+
+var_dump($obj[0]);
+var_dump($obj[2]);
+
+$x = $obj[6] = 'changed 6';
+var_dump($obj[6]);
+var_dump($x);
+
+print "Done\n";
+?>
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ int(1)
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ int(4)
+}
+c::exists(0)
+c::get(0)
+string(3) "1st"
+c::exists(1)
+c::get(1)
+int(1)
+c::exists(2)
+c::get(2)
+string(3) "3rd"
+c::exists(4th)
+c::get(4th)
+int(4)
+c::exists(5th)
+
+Notice: Undefined index: 5th in %s on line %d
+NULL
+c::exists(6)
+
+Notice: Undefined index: 6 in %s on line %d
+NULL
+WRITE 1
+c::exists(1)
+c::set(1,Changed 1)
+
+Warning: Method c::set() did not return a value, using NULL in %s on line %d
+c::exists(1)
+c::get(1)
+string(9) "Changed 1"
+WRITE 2
+c::exists(4th)
+c::set(4th,Changed 4th)
+
+Warning: Method c::set() did not return a value, using NULL in %s on line %d
+c::exists(4th)
+c::get(4th)
+string(11) "Changed 4th"
+WRITE 3
+c::exists(5th)
+c::set(5th,Added 5th)
+
+Warning: Method c::set() did not return a value, using NULL in %s on line %d
+c::exists(5th)
+c::get(5th)
+string(9) "Added 5th"
+WRITE 4
+c::exists(6)
+c::set(6,Added 6)
+
+Warning: Method c::set() did not return a value, using NULL in %s on line %d
+c::exists(6)
+c::get(6)
+string(7) "Added 6"
+c::exists(0)
+c::get(0)
+string(3) "1st"
+c::exists(2)
+c::get(2)
+string(3) "3rd"
+c::exists(6)
+c::set(6,changed 6)
+
+Warning: Method c::set() did not return a value, using NULL in %s on line %d
+c::exists(6)
+c::get(6)
+string(9) "changed 6"
+NULL
+Done
diff --git a/ext/spl/tests/array_access_ex.phpt b/ext/spl/tests/array_access_ex.phpt
new file mode 100755
index 0000000000..2800c0508e
--- /dev/null
+++ b/ext/spl/tests/array_access_ex.phpt
@@ -0,0 +1,154 @@
+--TEST--
+SPL: array_access
+--SKIPIF--
+<?php
+ if (!extension_loaded("spl")) die("skip");
+ if (!in_array("spl::array_access",spl_classes())) die("skip spl::array_access not present");
+?>
+--FILE--
+<?php
+class array_write implements spl::array_writer {
+ private $obj;
+ private $idx;
+
+ function __construct(&$obj, $index = null) {
+ $this->obj = &$obj;
+ $this->idx = $index;
+ }
+
+ function set($value) {
+ echo __METHOD__ . "($value,".$this->idx.")\n";
+ return $this->obj->set($this->idx, $value);
+ }
+}
+
+class c implements spl::array_access_ex {
+
+ public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+ function new_writer($index) {
+ return new array_write(&$this, $index);
+ }
+
+ function exists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $this->a);
+ }
+
+ function get($index) {
+ echo __METHOD__ . "($index)\n";
+ return $this->a[$index];
+ }
+
+ function set($index, $newval) {
+ echo __METHOD__ . "($index,$newval)\n";
+ return $this->a[$index] = $newval;
+ }
+}
+
+$obj = new c();
+
+var_dump($obj->a);
+
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+echo "WRITE 1\n";
+$obj[1] = 'Changed 1';
+var_dump($obj[1]);
+echo "WRITE 2\n";
+$obj['4th'] = 'Changed 4th';
+var_dump($obj['4th']);
+echo "WRITE 3\n";
+$obj['5th'] = 'Added 5th';
+var_dump($obj['5th']);
+echo "WRITE 4\n";
+$obj[6] = 'Added 6';
+var_dump($obj[6]);
+
+var_dump($obj[0]);
+var_dump($obj[2]);
+
+$x = $obj[6] = 'changed 6';
+var_dump($obj[6]);
+var_dump($x);
+
+print "Done\n";
+?>
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ int(1)
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ int(4)
+}
+c::exists(0)
+c::get(0)
+string(3) "1st"
+c::exists(1)
+c::get(1)
+int(1)
+c::exists(2)
+c::get(2)
+string(3) "3rd"
+c::exists(4th)
+c::get(4th)
+int(4)
+c::exists(5th)
+
+Notice: Undefined index: 5th in /usr/src/php5/ext/spl/tests/array_access_ex.php on line 49
+NULL
+c::exists(6)
+
+Notice: Undefined index: 6 in /usr/src/php5/ext/spl/tests/array_access_ex.php on line 50
+NULL
+WRITE 1
+c::exists(1)
+array_write::set(Changed 1,1)
+c::set(1,Changed 1)
+c::exists(1)
+c::get(1)
+string(9) "Changed 1"
+WRITE 2
+c::exists(4th)
+array_write::set(Changed 4th,4th)
+c::set(4th,Changed 4th)
+c::exists(4th)
+c::get(4th)
+string(11) "Changed 4th"
+WRITE 3
+c::exists(5th)
+array_write::set(Added 5th,5th)
+c::set(5th,Added 5th)
+c::exists(5th)
+c::get(5th)
+string(9) "Added 5th"
+WRITE 4
+c::exists(6)
+array_write::set(Added 6,6)
+c::set(6,Added 6)
+c::exists(6)
+c::get(6)
+string(7) "Added 6"
+c::exists(0)
+c::get(0)
+string(3) "1st"
+c::exists(2)
+c::get(2)
+string(3) "3rd"
+c::exists(6)
+array_write::set(changed 6,6)
+c::set(6,changed 6)
+c::exists(6)
+c::get(6)
+string(9) "changed 6"
+string(9) "changed 6"
+Done
diff --git a/ext/spl/tests/array_read.phpt b/ext/spl/tests/array_read.phpt
new file mode 100755
index 0000000000..b1e95fd6a1
--- /dev/null
+++ b/ext/spl/tests/array_read.phpt
@@ -0,0 +1,208 @@
+--TEST--
+SPL: array_read
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+echo "EXTERNAL\n";
+
+$a = array('1st', 1, 2=>'3rd', '4th'=>4);
+var_dump($a);
+
+class external implements spl::array_read {
+
+ function exists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $GLOBALS['a']);
+ }
+
+ function get($index) {
+ echo __METHOD__ . "($index)\n";
+ return $GLOBALS['a'][$index];
+ }
+}
+
+$obj = new external();
+
+var_dump($obj->get(0));
+var_dump($obj->get(1));
+var_dump($obj->get(2));
+var_dump($obj->get('4th'));
+var_dump($obj->get('5th'));
+var_dump($obj->get(6));
+
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+$out = $obj[0]; echo "$out\n";
+$out = $obj[1]; echo "$out\n";
+$out = $obj[2]; echo "$out\n";
+$out = $obj['4th']; echo "$out\n";
+
+echo "INTERNAL\n";
+
+class internal implements spl::array_read {
+
+ public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+ function exists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $GLOBALS['a']);
+ }
+
+ function get($index) {
+ echo __METHOD__ . "($index)\n";
+ return $GLOBALS['a'][$index];
+ }
+}
+
+$obj = new internal();
+
+var_dump($obj->a);
+
+var_dump($obj->get(0));
+var_dump($obj->get(1));
+var_dump($obj->get(2));
+var_dump($obj->get('4th'));
+var_dump($obj->get('5th'));
+var_dump($obj->get(6));
+
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+$out = $obj[0]; echo "$out\n";
+$out = $obj[1]; echo "$out\n";
+$out = $obj[2]; echo "$out\n";
+$out = $obj['4th']; echo "$out\n";
+
+print "Done\n";
+?>
+--EXPECTF--
+EXTERNAL
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ int(1)
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ int(4)
+}
+external::get(0)
+string(3) "1st"
+external::get(1)
+int(1)
+external::get(2)
+string(3) "3rd"
+external::get(4th)
+int(4)
+external::get(5th)
+
+Notice: Undefined index: 5th in %s on line %d
+NULL
+external::get(6)
+
+Notice: Undefined offset: 6 in %s on line %d
+NULL
+external::exists(0)
+external::get(0)
+string(3) "1st"
+external::exists(1)
+external::get(1)
+int(1)
+external::exists(2)
+external::get(2)
+string(3) "3rd"
+external::exists(4th)
+external::get(4th)
+int(4)
+external::exists(5th)
+
+Notice: Undefined index: 5th in %s on line %d
+NULL
+external::exists(6)
+
+Notice: Undefined index: 6 in %s on line %d
+NULL
+external::exists(0)
+external::get(0)
+1st
+external::exists(1)
+external::get(1)
+1
+external::exists(2)
+external::get(2)
+3rd
+external::exists(4th)
+external::get(4th)
+4
+INTERNAL
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ int(1)
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ int(4)
+}
+internal::get(0)
+string(3) "1st"
+internal::get(1)
+int(1)
+internal::get(2)
+string(3) "3rd"
+internal::get(4th)
+int(4)
+internal::get(5th)
+
+Notice: Undefined index: 5th in %s on line %d
+NULL
+internal::get(6)
+
+Notice: Undefined offset: 6 in %s on line %d
+NULL
+internal::exists(0)
+internal::get(0)
+string(3) "1st"
+internal::exists(1)
+internal::get(1)
+int(1)
+internal::exists(2)
+internal::get(2)
+string(3) "3rd"
+internal::exists(4th)
+internal::get(4th)
+int(4)
+internal::exists(5th)
+
+Notice: Undefined index: 5th in %s on line %d
+NULL
+internal::exists(6)
+
+Notice: Undefined index: 6 in %s on line %d
+NULL
+internal::exists(0)
+internal::get(0)
+1st
+internal::exists(1)
+internal::get(1)
+1
+internal::exists(2)
+internal::get(2)
+3rd
+internal::exists(4th)
+internal::get(4th)
+4
+Done
diff --git a/ext/spl/tests/foreach.phpt b/ext/spl/tests/foreach.phpt
new file mode 100755
index 0000000000..6803e44c27
--- /dev/null
+++ b/ext/spl/tests/foreach.phpt
@@ -0,0 +1,184 @@
+--TEST--
+SPL: foreach and iterator
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+class c_iter implements spl::forward_assoc {
+
+ private $obj;
+ private $num = 0;
+
+ function __construct($obj) {
+ $this->obj = $obj;
+ }
+ function current() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ return $this->num;
+ }
+ function next() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ $this->num++;
+ }
+ function has_more() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ return $this->num < $this->obj->max;
+ }
+ function key() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ switch($this->num) {
+ case 0: return "1st";
+ case 1: return "2nd";
+ case 2: return "3rd";
+ default: return "???";
+ }
+ }
+}
+
+class c implements spl::iterator {
+
+ public $max = 3;
+
+ function new_iterator() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ return new c_iter($this);
+ }
+}
+
+$t = new c();
+
+for ($iter = $t->new_iterator(); $iter->has_more(); $iter->next()) {
+ echo $iter->current() . "\n";
+}
+
+$a = array(0,1,2);
+foreach($a as $v) {
+ echo "array:$v\n";
+}
+
+foreach($t as $v) {
+ echo "object:$v\n";
+}
+
+foreach($t as $v) {
+ foreach($t as $w) {
+ echo "double:$v:$w\n";
+ }
+}
+
+foreach($t as $i => $v) {
+ echo "object:$i=>$v\n";
+}
+
+print "Done\n";
+?>
+--EXPECT--
+c::new_iterator
+c_iter::has_more
+c_iter::current
+0
+c_iter::next
+c_iter::has_more
+c_iter::current
+1
+c_iter::next
+c_iter::has_more
+c_iter::current
+2
+c_iter::next
+c_iter::has_more
+array:0
+array:1
+array:2
+c::new_iterator
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:0
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:1
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:2
+c_iter::next
+c_iter::has_more
+c::new_iterator
+c_iter::has_more
+c_iter::current
+c_iter::key
+c::new_iterator
+c_iter::has_more
+c_iter::current
+c_iter::key
+double:0:0
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+double:0:1
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+double:0:2
+c_iter::next
+c_iter::has_more
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+c::new_iterator
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+double:1:1
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+double:1:2
+c_iter::next
+c_iter::has_more
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+c::new_iterator
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+double:2:1
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+double:2:2
+c_iter::next
+c_iter::has_more
+c_iter::next
+c_iter::has_more
+c::new_iterator
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:1st=>0
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:2nd=>1
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:3rd=>2
+c_iter::next
+c_iter::has_more
+Done \ No newline at end of file
diff --git a/ext/spl/tests/forward.phpt b/ext/spl/tests/forward.phpt
new file mode 100755
index 0000000000..2c8a584b8a
--- /dev/null
+++ b/ext/spl/tests/forward.phpt
@@ -0,0 +1,115 @@
+--TEST--
+SPL: forward
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+class c implements spl::forward_assoc {
+
+ public $max = 3;
+ public $num = 0;
+
+ function current() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ return $this->num;
+ }
+ function next() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ $this->num++;
+ }
+ function has_more() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ return $this->num < $this->max;
+ }
+ function key() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ switch($this->num) {
+ case 0: return "1st";
+ case 1: return "2nd";
+ case 2: return "3rd";
+ default: return "???";
+ }
+ }
+}
+
+$i = new c();
+
+$c_info = array(class_name($i) => array('inheits' => class_parents($i), 'implements' => class_implements($i)));
+print_r($c_info);
+
+echo "1st try\n";
+foreach($i as $w) {
+ echo "object:$w\n";
+}
+
+echo "2nd try\n";
+
+foreach($i as $v => $w) {
+ echo "object:$v=>$w\n";
+}
+
+echo "3rd try\n";
+$i->num = 0;
+
+foreach($i as $v => $w) {
+ echo "object:$v=>$w\n";
+}
+
+print "Done\n";
+?>
+--EXPECT--
+Array
+(
+ [c] => Array
+ (
+ [inheits] => Array
+ (
+ )
+
+ [implements] => Array
+ (
+ [spl::forward_assoc] => spl::forward_assoc
+ [spl::assoc] => spl::assoc
+ [spl::forward] => spl::forward
+ )
+
+ )
+
+)
+1st try
+c::has_more
+c::current
+c::key
+object:0
+c::next
+c::has_more
+c::current
+c::key
+object:1
+c::next
+c::has_more
+c::current
+c::key
+object:2
+c::next
+c::has_more
+2nd try
+c::has_more
+3rd try
+c::has_more
+c::current
+c::key
+object:1st=>0
+c::next
+c::has_more
+c::current
+c::key
+object:2nd=>1
+c::next
+c::has_more
+c::current
+c::key
+object:3rd=>2
+c::next
+c::has_more
+Done \ No newline at end of file
diff --git a/ext/spl/tests/sequence.phpt b/ext/spl/tests/sequence.phpt
new file mode 100755
index 0000000000..3608e15c41
--- /dev/null
+++ b/ext/spl/tests/sequence.phpt
@@ -0,0 +1,138 @@
+--TEST--
+SPL: sequence
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+class c implements spl::iterator {
+
+ public $max = 3;
+
+ function new_iterator() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ return new c_iter($this);
+ }
+}
+
+class c_iter implements spl::sequence_assoc {
+
+ private $obj;
+ private $num = 0;
+
+ function __construct($obj) {
+ $this->obj = $obj;
+ }
+ function rewind() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ $this->num = 0;
+ }
+ function current() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ return $this->num;
+ }
+ function next() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ $this->num++;
+ }
+ function has_more() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ return $this->num < $this->obj->max;
+ }
+ function key() {
+ echo __CLASS__ . '::' . __FUNCTION__ . "\n";
+ switch($this->num) {
+ case 0: return "1st";
+ case 1: return "2nd";
+ case 2: return "3rd";
+ default: return "???";
+ }
+ }
+}
+
+$t = new c();
+$i = $t->new_iterator();
+
+$c_info = array(class_name($t) => array('inheits' => class_parents($t), 'implements' => class_implements($t)),
+ class_name($i) => array('inheits' => class_parents($i), 'implements' => class_implements($i)));
+print_r($c_info);
+
+foreach($i as $w) {
+ echo "object:$w\n";
+}
+
+foreach($i as $v => $w) {
+ echo "object:$v=>$w\n";
+}
+
+print "Done\n";
+?>
+--EXPECT--
+c::new_iterator
+Array
+(
+ [c] => Array
+ (
+ [inheits] => Array
+ (
+ )
+
+ [implements] => Array
+ (
+ [spl::iterator] => spl::iterator
+ )
+
+ )
+
+ [c_iter] => Array
+ (
+ [inheits] => Array
+ (
+ )
+
+ [implements] => Array
+ (
+ [spl::sequence_assoc] => spl::sequence_assoc
+ [spl::forward_assoc] => spl::forward_assoc
+ [spl::assoc] => spl::assoc
+ [spl::forward] => spl::forward
+ [spl::sequence] => spl::sequence
+ )
+
+ )
+
+)
+c_iter::rewind
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:0
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:1
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:2
+c_iter::next
+c_iter::has_more
+c_iter::rewind
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:1st=>0
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:2nd=>1
+c_iter::next
+c_iter::has_more
+c_iter::current
+c_iter::key
+object:3rd=>2
+c_iter::next
+c_iter::has_more
+Done \ No newline at end of file