2003-05-01 23:28:28 +00:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| 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"
|
|
|
|
|
2003-05-25 01:36:50 +00:00
|
|
|
#define OPTIMIZED_ARRAY_CONSTRUCT
|
|
|
|
|
2003-05-24 13:47:49 +00:00
|
|
|
#define ezalloc(size) \
|
|
|
|
memset(emalloc(size), 0, size)
|
|
|
|
|
|
|
|
typedef struct {
|
2003-06-09 16:57:17 +00:00
|
|
|
zend_function *next;
|
|
|
|
zend_function *rewind;
|
|
|
|
zend_function *more;
|
|
|
|
zend_function *current;
|
|
|
|
zend_function *key;
|
|
|
|
} spl_foreach_funcs;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
zval *obj;
|
|
|
|
zend_class_entry *obj_ce;
|
|
|
|
zend_uint index;
|
|
|
|
spl_is_a is_a;
|
|
|
|
spl_foreach_funcs funcs;
|
|
|
|
char dummy; /* needed for '\0' but we can't set it due to compiler optimizations */
|
2003-05-24 13:47:49 +00:00
|
|
|
} spl_foreach_proxy;
|
|
|
|
|
2003-05-01 23:28:28 +00:00
|
|
|
/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET) */
|
|
|
|
ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET)
|
|
|
|
{
|
|
|
|
zval **obj, *retval;
|
2003-06-09 16:57:17 +00:00
|
|
|
spl_foreach_proxy *proxy;
|
2003-05-29 21:08:08 +00:00
|
|
|
zend_class_entry *instance_ce;
|
2003-05-31 15:22:42 +00:00
|
|
|
spl_is_a is_a;
|
2003-05-25 19:10:44 +00:00
|
|
|
|
|
|
|
obj = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
|
2003-05-29 21:08:08 +00:00
|
|
|
|
2003-05-31 15:22:42 +00:00
|
|
|
if (!obj || (instance_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) {
|
|
|
|
ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
|
2003-05-29 21:08:08 +00:00
|
|
|
}
|
|
|
|
|
2003-05-31 15:22:42 +00:00
|
|
|
is_a = spl_implements(instance_ce);
|
|
|
|
|
2003-05-29 21:08:08 +00:00
|
|
|
if (is_a & SPL_IS_A_ITERATOR) {
|
2003-05-25 19:10:44 +00:00
|
|
|
spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
|
|
|
|
spl_begin_method_call_ex(obj, NULL, NULL, "new_iterator", sizeof("new_iterator")-1, &retval TSRMLS_CC);
|
2003-05-29 21:08:08 +00:00
|
|
|
instance_ce = spl_get_class_entry(retval TSRMLS_CC);
|
|
|
|
is_a = spl_implements(instance_ce);
|
|
|
|
if (!(is_a & SPL_IS_A_FORWARD)) {
|
2003-05-25 19:10:44 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Objects created by new_iterator() must implement spl::forward");
|
|
|
|
ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
|
2003-05-01 23:28:28 +00:00
|
|
|
}
|
2003-05-25 19:10:44 +00:00
|
|
|
PZVAL_LOCK(retval);
|
2003-05-29 21:08:08 +00:00
|
|
|
} else if (is_a & SPL_IS_A_FORWARD) {
|
2003-05-25 19:10:44 +00:00
|
|
|
spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
|
|
|
|
(*obj)->refcount += 2; /* lock two times */
|
|
|
|
retval = *obj;
|
|
|
|
} else {
|
|
|
|
ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_RESET);
|
2003-05-01 23:28:28 +00:00
|
|
|
}
|
2003-05-25 19:10:44 +00:00
|
|
|
|
|
|
|
/* create the proxy */
|
2003-06-09 16:57:17 +00:00
|
|
|
proxy = emalloc(sizeof(spl_foreach_proxy));
|
|
|
|
proxy->obj = retval;
|
|
|
|
proxy->obj_ce = instance_ce;
|
|
|
|
proxy->index = 0;
|
|
|
|
proxy->is_a = is_a;
|
|
|
|
memset(&proxy->funcs, 0, sizeof(spl_foreach_funcs));
|
|
|
|
((char*)proxy)[sizeof(spl_foreach_proxy)-1] = '\0';
|
2003-05-25 19:10:44 +00:00
|
|
|
/* And pack it into a zval. Since it is nowhere accessible using a
|
|
|
|
* zval of type STRING is the fastest approach of storing the proxy.
|
|
|
|
*/
|
|
|
|
ALLOC_INIT_ZVAL(retval);
|
2003-06-09 16:57:17 +00:00
|
|
|
ZVAL_STRINGL(retval, (char*)proxy, sizeof(spl_foreach_proxy)-1, 0);
|
2003-05-25 19:10:44 +00:00
|
|
|
retval->refcount += 2; /* lock two times */
|
|
|
|
/* return the created proxy container */
|
|
|
|
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;
|
|
|
|
|
|
|
|
NEXT_OPCODE();
|
2003-05-01 23:28:28 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2003-05-25 01:36:50 +00:00
|
|
|
/* {{{ OPTIMIZED_ARRAY_CONSTRUCT macros */
|
|
|
|
#ifdef OPTIMIZED_ARRAY_CONSTRUCT
|
2003-05-24 21:02:33 +00:00
|
|
|
#define CONNECT_TO_BUCKET_DLLIST(element, list_head) \
|
|
|
|
(element)->pNext = (list_head); \
|
2003-05-25 01:36:50 +00:00
|
|
|
(element)->pLast = NULL;
|
2003-05-24 21:02:33 +00:00
|
|
|
|
|
|
|
#define CONNECT_TO_GLOBAL_DLLIST(element, ht) \
|
|
|
|
(element)->pListLast = (ht)->pListTail; \
|
|
|
|
(ht)->pListTail = (element); \
|
|
|
|
(element)->pListNext = NULL; \
|
|
|
|
if ((element)->pListLast != NULL) { \
|
|
|
|
(element)->pListLast->pListNext = (element); \
|
|
|
|
} \
|
|
|
|
if (!(ht)->pListHead) { \
|
|
|
|
(ht)->pListHead = (element); \
|
|
|
|
} \
|
|
|
|
if ((ht)->pInternalPointer == NULL) { \
|
|
|
|
(ht)->pInternalPointer = (element); \
|
|
|
|
}
|
2003-05-25 01:36:50 +00:00
|
|
|
#endif
|
|
|
|
/* }}} */
|
2003-05-24 21:02:33 +00:00
|
|
|
|
2003-05-01 23:28:28 +00:00
|
|
|
/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH) */
|
|
|
|
ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_FETCH)
|
|
|
|
{
|
2003-05-24 21:02:33 +00:00
|
|
|
znode *op1 = &EX(opline)->op1;
|
|
|
|
zval **obj = spl_get_zval_ptr_ptr(op1, EX(Ts) TSRMLS_CC);
|
2003-05-01 23:28:28 +00:00
|
|
|
zval more, tmp, *value, *key, *result;
|
2003-05-25 19:10:44 +00:00
|
|
|
spl_foreach_proxy *proxy;
|
2003-05-01 23:28:28 +00:00
|
|
|
|
2003-05-25 19:10:44 +00:00
|
|
|
if (Z_TYPE_PP(obj) == IS_STRING) {
|
2003-05-24 21:02:33 +00:00
|
|
|
spl_unlock_zval_ptr_ptr(op1, EX(Ts) TSRMLS_CC);
|
2003-05-01 23:28:28 +00:00
|
|
|
PZVAL_LOCK(*obj);
|
|
|
|
|
2003-05-25 19:10:44 +00:00
|
|
|
proxy = (spl_foreach_proxy*)Z_STRVAL_PP(obj);
|
|
|
|
obj = &proxy->obj; /* will be optimized out */
|
|
|
|
|
2003-05-24 13:47:49 +00:00
|
|
|
if (proxy->index++) {
|
2003-06-09 16:57:17 +00:00
|
|
|
spl_begin_method_call_this(obj, proxy->obj_ce, &proxy->funcs.next, "next", sizeof("next")-1, &tmp TSRMLS_CC);
|
2003-05-24 21:02:33 +00:00
|
|
|
} else {
|
2003-05-29 21:08:08 +00:00
|
|
|
if (proxy->is_a & SPL_IS_A_SEQUENCE) {
|
2003-06-09 16:57:17 +00:00
|
|
|
spl_begin_method_call_this(obj, proxy->obj_ce, &proxy->funcs.rewind, "rewind", sizeof("rewind")-1, &tmp TSRMLS_CC);
|
2003-05-24 21:02:33 +00:00
|
|
|
}
|
2003-05-25 19:10:44 +00:00
|
|
|
op_array->opcodes[EX(opline)->op2.u.opline_num].op2 = *op1;
|
2003-05-01 23:28:28 +00:00
|
|
|
}
|
|
|
|
|
2003-06-09 16:57:17 +00:00
|
|
|
spl_begin_method_call_this(obj, proxy->obj_ce, &proxy->funcs.more, "has_more", sizeof("has_more")-1, &more TSRMLS_CC);
|
2003-05-01 23:28:28 +00:00
|
|
|
if (zend_is_true(&more)) {
|
|
|
|
result = &EX_T(EX(opline)->result.u.var).tmp_var;
|
|
|
|
|
2003-06-09 16:57:17 +00:00
|
|
|
spl_begin_method_call_ex(obj, proxy->obj_ce, &proxy->funcs.current, "current", sizeof("current")-1, &value TSRMLS_CC);
|
2003-05-01 23:28:28 +00:00
|
|
|
|
2003-05-29 21:08:08 +00:00
|
|
|
if (proxy->is_a & SPL_IS_A_ASSOC) {
|
2003-06-09 16:57:17 +00:00
|
|
|
spl_begin_method_call_ex(obj, proxy->obj_ce, &proxy->funcs.key, "key", sizeof("key")-1, &key TSRMLS_CC);
|
2003-05-01 23:28:28 +00:00
|
|
|
} else {
|
2003-05-24 21:02:33 +00:00
|
|
|
MAKE_STD_ZVAL(key);
|
|
|
|
key->value.lval = proxy->index;
|
|
|
|
key->type = IS_LONG;
|
2003-05-01 23:28:28 +00:00
|
|
|
}
|
2003-05-25 01:36:50 +00:00
|
|
|
#ifndef OPTIMIZED_ARRAY_CONSTRUCT
|
|
|
|
array_init(result);
|
2003-05-24 21:02:33 +00:00
|
|
|
zend_hash_index_update(result->value.ht, 0, &value, sizeof(zval *), NULL);
|
2003-05-01 23:28:28 +00:00
|
|
|
zend_hash_index_update(result->value.ht, 1, &key, sizeof(zval *), NULL);
|
2003-05-25 01:36:50 +00:00
|
|
|
#else
|
2003-05-24 21:02:33 +00:00
|
|
|
{
|
|
|
|
Bucket *p;
|
2003-05-25 01:36:50 +00:00
|
|
|
HashTable *ht;
|
|
|
|
|
|
|
|
ht = emalloc(sizeof(HashTable));
|
|
|
|
result->value.ht = ht;
|
|
|
|
ht->nTableSize = 1 << 1;
|
|
|
|
ht->nTableMask = ht->nTableSize - 1;
|
|
|
|
#if ZEND_DEBUG
|
|
|
|
ht->inconsistent = 0; /*HT_OK;*/
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ht->arBuckets = (Bucket **)emalloc(ht->nTableSize * sizeof(Bucket *));
|
2003-05-24 21:02:33 +00:00
|
|
|
|
2003-05-25 01:36:50 +00:00
|
|
|
ht->pDestructor = ZVAL_PTR_DTOR;
|
|
|
|
ht->pListHead = NULL;
|
|
|
|
ht->pListTail = NULL;
|
|
|
|
ht->nNumOfElements = 0;
|
|
|
|
ht->nNextFreeElement = 0;
|
|
|
|
ht->pInternalPointer = NULL;
|
|
|
|
ht->persistent = 0;
|
|
|
|
ht->nApplyCount = 0;
|
|
|
|
ht->bApplyProtection = 1;
|
|
|
|
result->type = IS_ARRAY;
|
|
|
|
|
2003-05-24 21:02:33 +00:00
|
|
|
p = (Bucket*)emalloc(sizeof(Bucket)-1);
|
|
|
|
p->pDataPtr = value;
|
|
|
|
p->pData = &p->pDataPtr;
|
|
|
|
p->nKeyLength = 0;
|
|
|
|
p->h = 0;
|
|
|
|
result->value.ht->arBuckets[0] = p;
|
2003-05-25 01:36:50 +00:00
|
|
|
CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[0]);
|
|
|
|
CONNECT_TO_GLOBAL_DLLIST(p, ht);
|
|
|
|
|
2003-05-24 21:02:33 +00:00
|
|
|
p = (Bucket*)emalloc(sizeof(Bucket)-1);
|
|
|
|
p->pDataPtr = key;
|
|
|
|
p->pData = &p->pDataPtr;
|
|
|
|
p->nKeyLength = 0;
|
|
|
|
p->h = 1;
|
|
|
|
result->value.ht->arBuckets[1] = p;
|
2003-05-25 01:36:50 +00:00
|
|
|
CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[1]);
|
|
|
|
CONNECT_TO_GLOBAL_DLLIST(p, ht);
|
|
|
|
|
|
|
|
ht->nNumOfElements = 2;
|
2003-05-24 21:02:33 +00:00
|
|
|
}
|
2003-05-25 01:36:50 +00:00
|
|
|
#endif
|
2003-05-01 23:28:28 +00:00
|
|
|
NEXT_OPCODE();
|
|
|
|
}
|
|
|
|
EX(opline) = op_array->opcodes+EX(opline)->op2.u.opline_num;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FE_FETCH);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2003-05-25 19:10:44 +00:00
|
|
|
/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE) */
|
|
|
|
ZEND_EXECUTE_HOOK_FUNCTION(ZEND_SWITCH_FREE)
|
|
|
|
{
|
|
|
|
znode *op1 = &EX(opline)->op1;
|
|
|
|
znode *op2 = &EX(opline)->op2;
|
|
|
|
zval *tmp, **obj = spl_get_zval_ptr_ptr(op2, EX(Ts) TSRMLS_CC);
|
|
|
|
spl_foreach_proxy *proxy;
|
|
|
|
|
|
|
|
if (obj) {
|
|
|
|
proxy = (spl_foreach_proxy*)Z_STRVAL_PP(obj);
|
|
|
|
tmp = *obj;
|
|
|
|
*obj = proxy->obj; /* restore */
|
|
|
|
|
|
|
|
zval_dtor(tmp);
|
|
|
|
FREE_ZVAL(tmp);
|
|
|
|
|
|
|
|
spl_unlock_zval_ptr_ptr(op1, EX(Ts) TSRMLS_CC);
|
|
|
|
PZVAL_LOCK(*obj);
|
|
|
|
|
|
|
|
SET_UNUSED(*op2);
|
|
|
|
}
|
|
|
|
ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_SWITCH_FREE);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2003-05-01 23:28:28 +00:00
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* tab-width: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
|
|
|
* vim600: fdm=marker
|
|
|
|
* vim: noet sw=4 ts=4
|
|
|
|
*/
|