@@ -25,12 +25,14 @@ typedef struct {
25
25
bool by_ref ;
26
26
bool declared_props_done ;
27
27
zval declared_props ;
28
+ bool dynamic_props_done ;
28
29
uint32_t dynamic_prop_it ;
29
30
zval current_key ;
30
31
zval current_data ;
31
32
} zend_hooked_object_iterator ;
32
33
33
34
static zend_result zho_it_valid (zend_object_iterator * iter );
35
+ static void zho_it_move_forward (zend_object_iterator * iter );
34
36
35
37
// FIXME: This should probably be stored on zend_class_entry somewhere (e.g. through num_virtual_props).
36
38
static uint32_t zho_num_backed_props (zend_object * zobj )
@@ -87,13 +89,16 @@ ZEND_API zend_array *zend_hooked_object_build_properties(zend_object *zobj)
87
89
88
90
static bool zho_dynamic_it_init (zend_hooked_object_iterator * hooked_iter )
89
91
{
90
- zend_object * zobj = Z_OBJ_P (& hooked_iter -> it .data );
91
- if (!zobj -> properties ) {
92
- return false;
93
- }
94
92
if (hooked_iter -> dynamic_prop_it != (uint32_t ) -1 ) {
95
93
return true;
96
94
}
95
+
96
+ zend_object * zobj = Z_OBJ_P (& hooked_iter -> it .data );
97
+ if (!zobj -> properties || zho_num_backed_props (zobj ) == zobj -> properties -> nNumUsed ) {
98
+ hooked_iter -> dynamic_props_done = true;
99
+ return false;
100
+ }
101
+
97
102
hooked_iter -> dynamic_prop_it = zend_hash_iterator_add (zobj -> properties , zho_num_backed_props (zobj ));
98
103
return true;
99
104
}
@@ -102,39 +107,45 @@ static void zho_it_get_current_key(zend_object_iterator *iter, zval *key);
102
107
103
108
static void zho_declared_it_fetch_current (zend_object_iterator * iter )
104
109
{
105
- ZEND_ASSERT (zho_it_valid (iter ) == SUCCESS );
106
-
107
110
zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
108
- zval_ptr_dtor (& hooked_iter -> current_data );
109
- if (EG (exception )) {
110
- return ;
111
- }
112
- ZVAL_UNDEF (& hooked_iter -> current_data );
113
- zval_ptr_dtor (& hooked_iter -> current_key );
114
- ZVAL_UNDEF (& hooked_iter -> current_key );
115
111
zend_object * zobj = Z_OBJ_P (& iter -> data );
116
112
zend_array * properties = Z_ARR (hooked_iter -> declared_props );
117
113
118
- zval_ptr_dtor_nogc (& hooked_iter -> current_key );
119
- zend_hash_get_current_key_zval (properties , & hooked_iter -> current_key );
120
-
121
114
zval * property = zend_hash_get_current_data (properties );
122
115
if (Z_TYPE_P (property ) == IS_PTR ) {
123
116
zend_property_info * prop_info = Z_PTR_P (property );
124
117
zend_function * get = prop_info -> hooks [ZEND_PROPERTY_HOOK_GET ];
118
+ if (!get && (prop_info -> flags & ZEND_ACC_VIRTUAL )) {
119
+ return ;
120
+ }
125
121
if (hooked_iter -> by_ref
126
122
&& (get == NULL
127
123
|| !(get -> common .fn_flags & ZEND_ACC_RETURN_REFERENCE ))) {
128
124
zend_throw_error (NULL , "Cannot create reference to property %s::$%s" ,
129
125
ZSTR_VAL (zobj -> ce -> name ), zend_get_unmangled_property_name (prop_info -> name ));
130
126
return ;
131
127
}
132
- zend_read_property_ex (prop_info -> ce , zobj , prop_info -> name , /* silent */ true, & hooked_iter -> current_data );
128
+ zval * value = zend_read_property_ex (prop_info -> ce , zobj , prop_info -> name , /* silent */ true, & hooked_iter -> current_data );
129
+ if (value == & EG (uninitialized_zval )) {
130
+ return ;
131
+ } else if (value != & hooked_iter -> current_data ) {
132
+ ZVAL_COPY (& hooked_iter -> current_data , value );
133
+ }
133
134
} else {
134
135
ZVAL_DEINDIRECT (property );
135
- if (hooked_iter -> by_ref && Z_TYPE_P (property ) != IS_REFERENCE ) {
136
- ZEND_ASSERT (Z_TYPE_P (property ) != IS_UNDEF );
136
+ if (Z_TYPE_P (property ) == IS_UNDEF ) {
137
+ return ;
138
+ }
139
+ if (!hooked_iter -> by_ref ) {
140
+ ZVAL_DEREF (property );
141
+ } else if (Z_TYPE_P (property ) != IS_REFERENCE ) {
137
142
ZVAL_MAKE_REF (property );
143
+
144
+ zend_class_entry * ce = zobj -> ce ;
145
+ zend_property_info * prop_info = ce -> properties_info_table [OBJ_PROP_PTR_TO_NUM (zobj , property )];
146
+ if (ZEND_TYPE_IS_SET (prop_info -> type )) {
147
+ ZEND_REF_ADD_TYPE_SOURCE (Z_REF_P (property ), prop_info );
148
+ }
138
149
}
139
150
ZVAL_COPY (& hooked_iter -> current_data , property );
140
151
}
@@ -154,10 +165,8 @@ static void zho_dynamic_it_fetch_current(zend_object_iterator *iter)
154
165
ZEND_ASSERT (Z_TYPE (bucket -> val ) != IS_UNDEF );
155
166
ZVAL_MAKE_REF (& bucket -> val );
156
167
}
157
- zval_ptr_dtor (& hooked_iter -> current_data );
158
168
ZVAL_COPY (& hooked_iter -> current_data , & bucket -> val );
159
169
160
- zval_ptr_dtor_nogc (& hooked_iter -> current_key );
161
170
if (bucket -> key ) {
162
171
ZVAL_STR_COPY (& hooked_iter -> current_key , bucket -> key );
163
172
} else {
@@ -168,13 +177,22 @@ static void zho_dynamic_it_fetch_current(zend_object_iterator *iter)
168
177
static void zho_it_fetch_current (zend_object_iterator * iter )
169
178
{
170
179
zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
180
+ if (Z_TYPE (hooked_iter -> current_data ) != IS_UNDEF ) {
181
+ return ;
182
+ }
171
183
172
- if (!hooked_iter -> declared_props_done ) {
173
- zho_declared_it_fetch_current (iter );
174
- } else if (zho_dynamic_it_init (hooked_iter )) {
175
- zho_dynamic_it_fetch_current (iter );
176
- } else {
177
- ZEND_UNREACHABLE ();
184
+ while (true) {
185
+ if (!hooked_iter -> declared_props_done ) {
186
+ zho_declared_it_fetch_current (iter );
187
+ } else if (!hooked_iter -> dynamic_props_done && zho_dynamic_it_init (hooked_iter )) {
188
+ zho_dynamic_it_fetch_current (iter );
189
+ } else {
190
+ break ;
191
+ }
192
+ if (Z_TYPE (hooked_iter -> current_data ) != IS_UNDEF || EG (exception )) {
193
+ break ;
194
+ }
195
+ zho_it_move_forward (iter );
178
196
}
179
197
}
180
198
@@ -185,7 +203,6 @@ static void zho_it_dtor(zend_object_iterator *iter)
185
203
zval_ptr_dtor (& hooked_iter -> declared_props );
186
204
zval_ptr_dtor_nogc (& hooked_iter -> current_key );
187
205
zval_ptr_dtor (& hooked_iter -> current_data );
188
- zval_ptr_dtor (& hooked_iter -> current_key );
189
206
if (hooked_iter -> dynamic_prop_it != (uint32_t ) -1 ) {
190
207
zend_hash_iterator_del (hooked_iter -> dynamic_prop_it );
191
208
}
@@ -194,78 +211,66 @@ static void zho_it_dtor(zend_object_iterator *iter)
194
211
static zend_result zho_it_valid (zend_object_iterator * iter )
195
212
{
196
213
zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
197
- if (!hooked_iter -> declared_props_done ) {
198
- if (zend_hash_has_more_elements (Z_ARR (hooked_iter -> declared_props )) == SUCCESS ) {
199
- return SUCCESS ;
200
- }
201
- }
202
-
203
- if (zho_dynamic_it_init (hooked_iter )) {
204
- zend_object * zobj = Z_OBJ_P (& hooked_iter -> it .data );
205
- HashPosition pos = zend_hash_iterator_pos (hooked_iter -> dynamic_prop_it , zobj -> properties );
206
- return pos < zobj -> properties -> nNumUsed ? SUCCESS : FAILURE ;
207
- }
208
-
209
- return FAILURE ;
214
+ zho_it_fetch_current (iter );
215
+ return Z_TYPE (hooked_iter -> current_data ) != IS_UNDEF ? SUCCESS : FAILURE ;
210
216
}
211
217
212
218
static zval * zho_it_get_current_data (zend_object_iterator * iter )
213
219
{
214
220
zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
221
+ zho_it_fetch_current (iter );
215
222
return & hooked_iter -> current_data ;
216
223
}
217
224
218
225
static void zho_it_get_current_key (zend_object_iterator * iter , zval * key )
219
226
{
220
227
zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
228
+ zho_it_fetch_current (iter );
221
229
ZVAL_COPY (key , & hooked_iter -> current_key );
222
230
}
223
231
224
232
static void zho_it_move_forward (zend_object_iterator * iter )
225
233
{
226
234
zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
227
- zend_array * properties = Z_ARR (hooked_iter -> declared_props );
235
+
236
+ zval_ptr_dtor (& hooked_iter -> current_data );
237
+ ZVAL_UNDEF (& hooked_iter -> current_data );
238
+ zval_ptr_dtor_nogc (& hooked_iter -> current_key );
239
+ ZVAL_UNDEF (& hooked_iter -> current_key );
240
+
228
241
if (!hooked_iter -> declared_props_done ) {
242
+ zend_array * properties = Z_ARR (hooked_iter -> declared_props );
229
243
zend_hash_move_forward (properties );
230
- if (zend_hash_has_more_elements (properties ) == SUCCESS ) {
231
- zho_declared_it_fetch_current (iter );
232
- } else {
244
+ if (zend_hash_has_more_elements (properties ) != SUCCESS ) {
233
245
hooked_iter -> declared_props_done = true;
234
- if (zho_dynamic_it_init (hooked_iter )) {
235
- zho_dynamic_it_fetch_current (iter );
236
- }
237
246
}
238
- } else if (zho_dynamic_it_init (hooked_iter )) {
247
+ } else if (! hooked_iter -> dynamic_props_done && zho_dynamic_it_init (hooked_iter )) {
239
248
zend_array * properties = Z_OBJ (iter -> data )-> properties ;
240
249
HashPosition pos = zend_hash_iterator_pos (hooked_iter -> dynamic_prop_it , properties );
241
- Bucket * bucket = properties -> arData + pos ;
242
- while (true) {
243
- pos ++ ;
244
- bucket ++ ;
245
- if (pos >= properties -> nNumUsed ) {
246
- break ;
247
- }
248
- if (Z_TYPE_INFO_P (& bucket -> val ) != IS_UNDEF ) {
249
- zho_dynamic_it_fetch_current (iter );
250
- break ;
251
- }
252
- }
250
+ pos ++ ;
253
251
EG (ht_iterators )[hooked_iter -> dynamic_prop_it ].pos = pos ;
252
+ if (pos >= properties -> nNumUsed ) {
253
+ hooked_iter -> dynamic_props_done = true;
254
+ }
254
255
}
255
256
}
256
257
257
258
static void zho_it_rewind (zend_object_iterator * iter )
258
259
{
259
260
zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
261
+
262
+ zval_ptr_dtor (& hooked_iter -> current_data );
263
+ ZVAL_UNDEF (& hooked_iter -> current_data );
264
+ zval_ptr_dtor_nogc (& hooked_iter -> current_key );
265
+ ZVAL_UNDEF (& hooked_iter -> current_key );
266
+
260
267
hooked_iter -> declared_props_done = false;
261
268
zend_array * properties = Z_ARR (hooked_iter -> declared_props );
262
269
zend_hash_internal_pointer_reset (properties );
270
+ hooked_iter -> dynamic_props_done = false;
263
271
if (hooked_iter -> dynamic_prop_it != (uint32_t ) -1 ) {
264
272
EG (ht_iterators )[hooked_iter -> dynamic_prop_it ].pos = zho_num_backed_props (Z_OBJ (iter -> data ));
265
273
}
266
- if (zho_it_valid (iter ) == SUCCESS ) {
267
- zho_it_fetch_current (iter );
268
- }
269
274
}
270
275
271
276
static HashTable * zho_it_get_gc (zend_object_iterator * iter , zval * * table , int * n )
@@ -301,6 +306,7 @@ ZEND_API zend_object_iterator *zend_hooked_object_get_iterator(zend_class_entry
301
306
iterator -> declared_props_done = false;
302
307
zend_array * properties = zho_build_properties_ex (Z_OBJ_P (object ), true, false);
303
308
ZVAL_ARR (& iterator -> declared_props , properties );
309
+ iterator -> dynamic_props_done = false;
304
310
iterator -> dynamic_prop_it = (uint32_t ) -1 ;
305
311
ZVAL_UNDEF (& iterator -> current_key );
306
312
ZVAL_UNDEF (& iterator -> current_data );
0 commit comments