@@ -25,12 +25,14 @@ typedef struct {
2525 bool by_ref ;
2626 bool declared_props_done ;
2727 zval declared_props ;
28+ bool dynamic_props_done ;
2829 uint32_t dynamic_prop_it ;
2930 zval current_key ;
3031 zval current_data ;
3132} zend_hooked_object_iterator ;
3233
3334static zend_result zho_it_valid (zend_object_iterator * iter );
35+ static void zho_it_move_forward (zend_object_iterator * iter );
3436
3537// FIXME: This should probably be stored on zend_class_entry somewhere (e.g. through num_virtual_props).
3638static 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)
8789
8890static bool zho_dynamic_it_init (zend_hooked_object_iterator * hooked_iter )
8991{
90- zend_object * zobj = Z_OBJ_P (& hooked_iter -> it .data );
91- if (!zobj -> properties ) {
92- return false;
93- }
9492 if (hooked_iter -> dynamic_prop_it != (uint32_t ) -1 ) {
9593 return true;
9694 }
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+
97102 hooked_iter -> dynamic_prop_it = zend_hash_iterator_add (zobj -> properties , zho_num_backed_props (zobj ));
98103 return true;
99104}
@@ -102,39 +107,45 @@ static void zho_it_get_current_key(zend_object_iterator *iter, zval *key);
102107
103108static void zho_declared_it_fetch_current (zend_object_iterator * iter )
104109{
105- ZEND_ASSERT (zho_it_valid (iter ) == SUCCESS );
106-
107110 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 );
115111 zend_object * zobj = Z_OBJ_P (& iter -> data );
116112 zend_array * properties = Z_ARR (hooked_iter -> declared_props );
117113
118- zval_ptr_dtor_nogc (& hooked_iter -> current_key );
119- zend_hash_get_current_key_zval (properties , & hooked_iter -> current_key );
120-
121114 zval * property = zend_hash_get_current_data (properties );
122115 if (Z_TYPE_P (property ) == IS_PTR ) {
123116 zend_property_info * prop_info = Z_PTR_P (property );
124117 zend_function * get = prop_info -> hooks [ZEND_PROPERTY_HOOK_GET ];
118+ if (!get && (prop_info -> flags & ZEND_ACC_VIRTUAL )) {
119+ return ;
120+ }
125121 if (hooked_iter -> by_ref
126122 && (get == NULL
127123 || !(get -> common .fn_flags & ZEND_ACC_RETURN_REFERENCE ))) {
128124 zend_throw_error (NULL , "Cannot create reference to property %s::$%s" ,
129125 ZSTR_VAL (zobj -> ce -> name ), zend_get_unmangled_property_name (prop_info -> name ));
130126 return ;
131127 }
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+ }
133134 } else {
134135 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 ) {
137142 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+ }
138149 }
139150 ZVAL_COPY (& hooked_iter -> current_data , property );
140151 }
@@ -154,10 +165,8 @@ static void zho_dynamic_it_fetch_current(zend_object_iterator *iter)
154165 ZEND_ASSERT (Z_TYPE (bucket -> val ) != IS_UNDEF );
155166 ZVAL_MAKE_REF (& bucket -> val );
156167 }
157- zval_ptr_dtor (& hooked_iter -> current_data );
158168 ZVAL_COPY (& hooked_iter -> current_data , & bucket -> val );
159169
160- zval_ptr_dtor_nogc (& hooked_iter -> current_key );
161170 if (bucket -> key ) {
162171 ZVAL_STR_COPY (& hooked_iter -> current_key , bucket -> key );
163172 } else {
@@ -168,13 +177,22 @@ static void zho_dynamic_it_fetch_current(zend_object_iterator *iter)
168177static void zho_it_fetch_current (zend_object_iterator * iter )
169178{
170179 zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
180+ if (Z_TYPE (hooked_iter -> current_data ) != IS_UNDEF ) {
181+ return ;
182+ }
171183
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 );
178196 }
179197}
180198
@@ -185,7 +203,6 @@ static void zho_it_dtor(zend_object_iterator *iter)
185203 zval_ptr_dtor (& hooked_iter -> declared_props );
186204 zval_ptr_dtor_nogc (& hooked_iter -> current_key );
187205 zval_ptr_dtor (& hooked_iter -> current_data );
188- zval_ptr_dtor (& hooked_iter -> current_key );
189206 if (hooked_iter -> dynamic_prop_it != (uint32_t ) -1 ) {
190207 zend_hash_iterator_del (hooked_iter -> dynamic_prop_it );
191208 }
@@ -194,78 +211,66 @@ static void zho_it_dtor(zend_object_iterator *iter)
194211static zend_result zho_it_valid (zend_object_iterator * iter )
195212{
196213 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 ;
210216}
211217
212218static zval * zho_it_get_current_data (zend_object_iterator * iter )
213219{
214220 zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
221+ zho_it_fetch_current (iter );
215222 return & hooked_iter -> current_data ;
216223}
217224
218225static void zho_it_get_current_key (zend_object_iterator * iter , zval * key )
219226{
220227 zend_hooked_object_iterator * hooked_iter = (zend_hooked_object_iterator * )iter ;
228+ zho_it_fetch_current (iter );
221229 ZVAL_COPY (key , & hooked_iter -> current_key );
222230}
223231
224232static void zho_it_move_forward (zend_object_iterator * iter )
225233{
226234 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+
228241 if (!hooked_iter -> declared_props_done ) {
242+ zend_array * properties = Z_ARR (hooked_iter -> declared_props );
229243 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 ) {
233245 hooked_iter -> declared_props_done = true;
234- if (zho_dynamic_it_init (hooked_iter )) {
235- zho_dynamic_it_fetch_current (iter );
236- }
237246 }
238- } else if (zho_dynamic_it_init (hooked_iter )) {
247+ } else if (! hooked_iter -> dynamic_props_done && zho_dynamic_it_init (hooked_iter )) {
239248 zend_array * properties = Z_OBJ (iter -> data )-> properties ;
240249 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 ++ ;
253251 EG (ht_iterators )[hooked_iter -> dynamic_prop_it ].pos = pos ;
252+ if (pos >= properties -> nNumUsed ) {
253+ hooked_iter -> dynamic_props_done = true;
254+ }
254255 }
255256}
256257
257258static void zho_it_rewind (zend_object_iterator * iter )
258259{
259260 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+
260267 hooked_iter -> declared_props_done = false;
261268 zend_array * properties = Z_ARR (hooked_iter -> declared_props );
262269 zend_hash_internal_pointer_reset (properties );
270+ hooked_iter -> dynamic_props_done = false;
263271 if (hooked_iter -> dynamic_prop_it != (uint32_t ) -1 ) {
264272 EG (ht_iterators )[hooked_iter -> dynamic_prop_it ].pos = zho_num_backed_props (Z_OBJ (iter -> data ));
265273 }
266- if (zho_it_valid (iter ) == SUCCESS ) {
267- zho_it_fetch_current (iter );
268- }
269274}
270275
271276static 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
301306 iterator -> declared_props_done = false;
302307 zend_array * properties = zho_build_properties_ex (Z_OBJ_P (object ), true, false);
303308 ZVAL_ARR (& iterator -> declared_props , properties );
309+ iterator -> dynamic_props_done = false;
304310 iterator -> dynamic_prop_it = (uint32_t ) -1 ;
305311 ZVAL_UNDEF (& iterator -> current_key );
306312 ZVAL_UNDEF (& iterator -> current_data );
0 commit comments