mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Add spl extension
This commit is contained in:
parent
0d46a490f7
commit
b5a70a72d1
24 changed files with 3042 additions and 0 deletions
2
ext/spl/CREDITS
Executable file
2
ext/spl/CREDITS
Executable file
|
@ -0,0 +1,2 @@
|
|||
SPL
|
||||
Marcus Boerger
|
0
ext/spl/EXPERIMENTAL
Executable file
0
ext/spl/EXPERIMENTAL
Executable file
13
ext/spl/TODO
Executable file
13
ext/spl/TODO
Executable file
|
@ -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
|
41
ext/spl/config.m4
Executable file
41
ext/spl/config.m4
Executable file
|
@ -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
|
72
ext/spl/examples/dba_dump.php
Executable file
72
ext/spl/examples/dba_dump.php
Executable file
|
@ -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";
|
||||
}
|
||||
|
||||
?>
|
310
ext/spl/php_spl.c
Executable file
310
ext/spl/php_spl.c
Executable file
|
@ -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
|
||||
*/
|
114
ext/spl/php_spl.h
Executable file
114
ext/spl/php_spl.h
Executable file
|
@ -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
|
||||
*/
|
306
ext/spl/spl.php
Executable file
306
ext/spl/spl.php
Executable file
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
349
ext/spl/spl_array.c
Executable file
349
ext/spl/spl_array.c
Executable file
|
@ -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
|
||||
*/
|
49
ext/spl/spl_array.h
Executable file
49
ext/spl/spl_array.h
Executable file
|
@ -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
|
||||
*/
|
223
ext/spl/spl_engine.c
Executable file
223
ext/spl/spl_engine.c
Executable file
|
@ -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
|
||||
*/
|
63
ext/spl/spl_engine.h
Executable file
63
ext/spl/spl_engine.h
Executable file
|
@ -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
|
||||
*/
|
130
ext/spl/spl_foreach.c
Executable file
130
ext/spl/spl_foreach.c
Executable file
|
@ -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
|
||||
*/
|
37
ext/spl/spl_foreach.h
Executable file
37
ext/spl/spl_foreach.h
Executable file
|
@ -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
|
||||
*/
|
187
ext/spl/spl_functions.c
Executable file
187
ext/spl/spl_functions.c
Executable file
|
@ -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
|
||||
*/
|
80
ext/spl/spl_functions.h
Executable file
80
ext/spl/spl_functions.h
Executable file
|
@ -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
|
||||
*/
|
3
ext/spl/tests/.htaccess
Executable file
3
ext/spl/tests/.htaccess
Executable file
|
@ -0,0 +1,3 @@
|
|||
<IfModule mod_autoindex.c>
|
||||
IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t *.php
|
||||
</IfModule>
|
127
ext/spl/tests/array_access_001.phpt
Executable file
127
ext/spl/tests/array_access_001.phpt
Executable file
|
@ -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
|
137
ext/spl/tests/array_access_002.phpt
Executable file
137
ext/spl/tests/array_access_002.phpt
Executable file
|
@ -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
|
154
ext/spl/tests/array_access_ex.phpt
Executable file
154
ext/spl/tests/array_access_ex.phpt
Executable file
|
@ -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
|
208
ext/spl/tests/array_read.phpt
Executable file
208
ext/spl/tests/array_read.phpt
Executable file
|
@ -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
|
184
ext/spl/tests/foreach.phpt
Executable file
184
ext/spl/tests/foreach.phpt
Executable file
|
@ -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
|
115
ext/spl/tests/forward.phpt
Executable file
115
ext/spl/tests/forward.phpt
Executable file
|
@ -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
|
138
ext/spl/tests/sequence.phpt
Executable file
138
ext/spl/tests/sequence.phpt
Executable file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue