diff options
-rwxr-xr-x | ext/spl/CREDITS | 2 | ||||
-rwxr-xr-x | ext/spl/EXPERIMENTAL | 0 | ||||
-rwxr-xr-x | ext/spl/TODO | 13 | ||||
-rwxr-xr-x | ext/spl/config.m4 | 41 | ||||
-rwxr-xr-x | ext/spl/examples/dba_dump.php | 72 | ||||
-rwxr-xr-x | ext/spl/php_spl.c | 310 | ||||
-rwxr-xr-x | ext/spl/php_spl.h | 114 | ||||
-rwxr-xr-x | ext/spl/spl.php | 306 | ||||
-rwxr-xr-x | ext/spl/spl_array.c | 349 | ||||
-rwxr-xr-x | ext/spl/spl_array.h | 49 | ||||
-rwxr-xr-x | ext/spl/spl_engine.c | 223 | ||||
-rwxr-xr-x | ext/spl/spl_engine.h | 63 | ||||
-rwxr-xr-x | ext/spl/spl_foreach.c | 130 | ||||
-rwxr-xr-x | ext/spl/spl_foreach.h | 37 | ||||
-rwxr-xr-x | ext/spl/spl_functions.c | 187 | ||||
-rwxr-xr-x | ext/spl/spl_functions.h | 80 | ||||
-rwxr-xr-x | ext/spl/tests/.htaccess | 3 | ||||
-rwxr-xr-x | ext/spl/tests/array_access_001.phpt | 127 | ||||
-rwxr-xr-x | ext/spl/tests/array_access_002.phpt | 137 | ||||
-rwxr-xr-x | ext/spl/tests/array_access_ex.phpt | 154 | ||||
-rwxr-xr-x | ext/spl/tests/array_read.phpt | 208 | ||||
-rwxr-xr-x | ext/spl/tests/foreach.phpt | 184 | ||||
-rwxr-xr-x | ext/spl/tests/forward.phpt | 115 | ||||
-rwxr-xr-x | ext/spl/tests/sequence.phpt | 138 |
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**)®_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 |