summaryrefslogtreecommitdiff
path: root/ext/spl/spl_foreach.c
blob: cbe7dfd1e2b9c536303cb3e400adb8d8fa22ee27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
   +----------------------------------------------------------------------+
   | 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_implements(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_implements(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_implements(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_implements(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_implements(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();
		}
		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
 */