com php-src: Implement consistent behavior for foreach by value over plain object: Zend/tests/foreach_010.phpt Zend/zend_com pile.c Zend/zend_execute.c Zend/zend_generators.c Zend/zend_vm_def.h Zend/zend_vm_execute.h

[email protected] (Rasmus Lerdorf)
Newsgroups php.cvs
Message-ID <[email protected]>
Commit:    5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1
Author:    Dmitry Stogov <[email protected]>         Fri, 30 Jan 2015 09:49:35 +0300
Parents:   4c5b385ff53ae9f0b52572e98c4db801f56603b0
Branches:  dstogov-foreach

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1

Log:
Implement consistent behavior for foreach by value over plain object

Changed paths:
  A  Zend/tests/foreach_010.phpt
  M  Zend/zend_compile.c
  M  Zend/zend_execute.c
  M  Zend/zend_generators.c
  M  Zend/zend_vm_def.h
  M  Zend/zend_vm_execute.h
diff_5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1.txt (text/plain, 61 KB)
diff --git a/Zend/tests/foreach_010.phpt b/Zend/tests/foreach_010.phpt
new file mode 100644
index 0000000..6ba7e7e
--- /dev/null
+++ b/Zend/tests/foreach_010.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Nested foreach by value over object and object modification with resize
+--FILE--
+<?php
+$o = (object)['a'=>0, 'b'=>1, 'c'=>2, 'd'=>3, 'e'=>4, 'f'=>5, 'g'=>6, 'h'=>7];
+unset($o->a, $o->b, $o->c, $o->d);
+foreach ($o as $v1) {
+	foreach ($o as $v2) {
+		echo "$v1-$v2\n";
+		if ($v1 == 5 && $v2 == 6) {
+			$o->i = 8;
+		}	
+	}
+}
+?>
+--EXPECT--
+4-4
+4-5
+4-6
+4-7
+5-4
+5-5
+5-6
+5-7
+5-8
+6-4
+6-5
+6-6
+6-7
+6-8
+7-4
+7-5
+7-6
+7-7
+7-8
+8-4
+8-5
+8-6
+8-7
+8-8
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 080b315..7929397 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -3398,7 +3398,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
 	opnum_reset = get_next_op_number(CG(active_op_array));
 	opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
 
-	reset_node.flag = by_ref;
+	reset_node.flag = 1; /* generate FE_FREE */
 	zend_stack_push(&CG(loop_var_stack), &reset_node);
 
 	opnum_fetch = get_next_op_number(CG(active_op_array));
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index d59aef1..1a81c29 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -1587,7 +1587,7 @@ static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_of
 			} else if (brk_opline->opcode == ZEND_FE_FREE) {
 				if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
 					zval *var = EX_VAR(brk_opline->op1.var);
-					if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+					if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
 						zend_hash_iterator_del(Z_FE_ITER_P(var));
 					}
 					zval_ptr_dtor_nogc(var);
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 1f25d07..971d4e7 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -62,7 +62,7 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato
 					zval_ptr_dtor_nogc(var);
 				} else if (brk_opline->opcode == ZEND_FE_FREE) {
 					zval *var = EX_VAR(brk_opline->op1.var);
-					if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+					if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
 						zend_hash_iterator_del(Z_FE_ITER_P(var));
 					}
 					zval_ptr_dtor_nogc(var);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 245bc0b..064c756 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2145,7 +2145,7 @@ ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
 
 	SAVE_OPLINE();
 	var = EX_VAR(opline->op1.var);
-	if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+	if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
 		zend_hash_iterator_del(Z_FE_ITER_P(var));
 	}
 	zval_ptr_dtor_nogc(var);
@@ -3839,7 +3839,7 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
 	} else if (brk_opline->opcode == ZEND_FE_FREE) {
 		if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
 			zval *var = EX_VAR(brk_opline->op1.var);
-			if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+			if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
 				zend_hash_iterator_del(Z_FE_ITER_P(var));
 			}
 			zval_ptr_dtor_nogc(var);
@@ -4647,70 +4647,105 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, ANY)
 {
 	USE_OPLINE
 	zend_free_op free_op1;
-	zval *array_ptr;
+	zval *array_ptr, *result;
 	HashTable *fe_ht;
 
 	SAVE_OPLINE();
 
 	array_ptr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
-	if (OP1_TYPE != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-		zend_bool is_empty;
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+		result = EX_VAR(opline->result.var);
+		ZVAL_COPY_VALUE(result, array_ptr);
+		if (OP1_TYPE != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+			Z_ADDREF_P(array_ptr);
+		}
+		Z_FE_POS_P(result) = 0;
 
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-			FREE_OP1();
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+		FREE_OP1_IF_VAR();
+		CHECK_EXCEPTION();
+		ZEND_VM_NEXT_OPCODE();
+	} else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			HashPosition pos = 0;
+			Bucket *p;
+
+			result = EX_VAR(opline->result.var);
+			ZVAL_COPY_VALUE(result, array_ptr);
+			if (OP1_TYPE != IS_TMP_VAR) {
+				Z_ADDREF_P(array_ptr);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			pos = 0;
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
+					FREE_OP1_IF_VAR();
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
 			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
+
+			FREE_OP1_IF_VAR();
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+				FREE_OP1();
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
+				HANDLE_EXCEPTION();
+			}
+
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
+					FREE_OP1();
+					HANDLE_EXCEPTION();
+				}
+			}
+
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
 			if (UNEXPECTED(EG(exception) != NULL)) {
 				OBJ_RELEASE(&iter->std);
 				FREE_OP1();
 				HANDLE_EXCEPTION();
 			}
-		}
-		
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
-				
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
-			FREE_OP1();
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
+			iter->index = -1; /* will be set to 0 before using next handler */
 
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-		FREE_OP1();
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		zval *result = EX_VAR(opline->result.var);
-
-		ZVAL_COPY_VALUE(result, array_ptr);
-		if (OP1_TYPE != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-			Z_ADDREF_P(array_ptr);
+			FREE_OP1();
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
 		}
-		Z_FE_POS_P(result) = 0;
-
-		FREE_OP1_IF_VAR();
-		CHECK_EXCEPTION();
-		ZEND_VM_NEXT_OPCODE();
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
+		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 		FREE_OP1();
 		ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 	}
@@ -4722,6 +4757,8 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
 	zend_free_op free_op1;
 	zval *array_ptr, *array_ref;
 	HashTable *fe_ht;
+	HashPosition pos = 0;
+	Bucket *p;
 
 	SAVE_OPLINE();
 
@@ -4734,70 +4771,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
 		array_ref = array_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
 	}
 
-	if (OP1_TYPE != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-		zend_bool is_empty;
-
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-			if (OP1_TYPE == IS_VAR) {
-				FREE_OP1_VAR_PTR();
-			} else {
-				FREE_OP1();
-			}
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
-			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
-
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
-			if (UNEXPECTED(EG(exception) != NULL)) {
-				OBJ_RELEASE(&iter->std);
-				if (OP1_TYPE == IS_VAR) {
-					FREE_OP1_VAR_PTR();
-				} else {
-					FREE_OP1();
-				}
-				HANDLE_EXCEPTION();
-			}
-		}
-		
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
-				
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
-			if (OP1_TYPE == IS_VAR) {
-				FREE_OP1_VAR_PTR();
-			} else {
-				FREE_OP1();
-			}
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
-
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-		if (OP1_TYPE == IS_VAR) {
-			FREE_OP1_VAR_PTR();
-		} else {
-			FREE_OP1();
-		}
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		HashPosition pos = 0;
-		Bucket *p;
-
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
 		if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
 			if (array_ptr == array_ref) {
 				ZVAL_NEW_REF(array_ref, array_ref);
@@ -4809,14 +4783,12 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
 			array_ptr = EX_VAR(opline->result.var);
 			ZVAL_COPY_VALUE(array_ptr, array_ref);
 		}
-		if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-			if (OP1_TYPE == IS_CONST) {
-				zval_copy_ctor_func(array_ptr);
-			} else {
-				SEPARATE_ARRAY(array_ptr);
-			}
-			fe_ht = Z_ARRVAL_P(array_ptr);
+		if (OP1_TYPE == IS_CONST) {
+			zval_copy_ctor_func(array_ptr);
+		} else {
+			SEPARATE_ARRAY(array_ptr);
 		}
+		fe_ht = Z_ARRVAL_P(array_ptr);
 		while (1) {
 			if (pos >= fe_ht->nNumUsed) {
 				FREE_OP1_VAR_PTR();
@@ -4824,12 +4796,9 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
 				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 			}
 			p = fe_ht->arData + pos;
-			if ((Z_TYPE(p->val) != IS_UNDEF &&
-			     (Z_TYPE(p->val) != IS_INDIRECT ||
-			      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-			    (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-			     !p->key ||
-			     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+			if (Z_TYPE(p->val) != IS_UNDEF &&
+			    (Z_TYPE(p->val) != IS_INDIRECT ||
+			     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
 				break;
 			}
 			pos++;
@@ -4840,6 +4809,102 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
 		FREE_OP1_VAR_PTR();
 		CHECK_EXCEPTION();
 		ZEND_VM_NEXT_OPCODE();
+	} else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
+				if (array_ptr == array_ref) {
+					ZVAL_NEW_REF(array_ref, array_ref);
+					array_ptr = Z_REFVAL_P(array_ref);
+				}
+				Z_ADDREF_P(array_ref);
+				ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+			} else {
+				array_ptr = EX_VAR(opline->result.var);
+				ZVAL_COPY_VALUE(array_ptr, array_ref);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
+					FREE_OP1_VAR_PTR();
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
+			}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
+
+			FREE_OP1_VAR_PTR();
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+				if (OP1_TYPE == IS_VAR) {
+					FREE_OP1_VAR_PTR();
+				} else {
+					FREE_OP1();
+				}
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
+				HANDLE_EXCEPTION();
+			}
+
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
+					if (OP1_TYPE == IS_VAR) {
+						FREE_OP1_VAR_PTR();
+					} else {
+						FREE_OP1();
+					}
+					HANDLE_EXCEPTION();
+				}
+			}
+
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+			if (UNEXPECTED(EG(exception) != NULL)) {
+				OBJ_RELEASE(&iter->std);
+				if (OP1_TYPE == IS_VAR) {
+					FREE_OP1_VAR_PTR();
+				} else {
+					FREE_OP1();
+				}
+				HANDLE_EXCEPTION();
+			}
+			iter->index = -1; /* will be set to 0 before using next handler */
+
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+			if (OP1_TYPE == IS_VAR) {
+				FREE_OP1_VAR_PTR();
+			} else {
+				FREE_OP1();
+			}
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
+		}
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -4906,7 +4971,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
  			zend_object *zobj = Z_OBJ_P(array);
 
  			fe_ht = Z_OBJPROP_P(array);
-			pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+			pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
 			while (1) {
 				if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
 					/* reached end of iteration */
@@ -4945,7 +5010,24 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
 				}
 			}
 			ZVAL_COPY(EX_VAR(opline->result.var), value);
-			Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
+			while (1) {
+				pos++;
+				if (pos >= fe_ht->nNumUsed) {
+					pos = INVALID_IDX;
+					break;
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (Z_TYPE_P(array) != IS_OBJECT ||
+				     !p->key ||
+				     zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) {
+					break;
+				}
+			}
+			EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+				fe_ht->nInternalPointer = pos;
 			ZEND_VM_INC_OPCODE();
 			ZEND_VM_NEXT_OPCODE();
 		} else {
@@ -5966,7 +6048,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
 				} else if (brk_opline->opcode == ZEND_FE_FREE) {
 					if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
 						zval *var = EX_VAR(brk_opline->op1.var);
-						if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+						if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
 							zend_hash_iterator_del(Z_FE_ITER_P(var));
 						}
 						zval_ptr_dtor_nogc(var);
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 4244f5f..8ae97d2 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1350,7 +1350,7 @@ static int ZEND_FASTCALL  ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
 				} else if (brk_opline->opcode == ZEND_FE_FREE) {
 					if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
 						zval *var = EX_VAR(brk_opline->op1.var);
-						if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+						if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
 							zend_hash_iterator_del(Z_FE_ITER_P(var));
 						}
 						zval_ptr_dtor_nogc(var);
@@ -1816,7 +1816,7 @@ static int ZEND_FASTCALL  ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 	} else if (brk_opline->opcode == ZEND_FE_FREE) {
 		if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
 			zval *var = EX_VAR(brk_opline->op1.var);
-			if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+			if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
 				zend_hash_iterator_del(Z_FE_ITER_P(var));
 			}
 			zval_ptr_dtor_nogc(var);
@@ -3059,68 +3059,102 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_R_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER
 {
 	USE_OPLINE
 
-	zval *array_ptr;
+	zval *array_ptr, *result;
 	HashTable *fe_ht;
 
 	SAVE_OPLINE();
 
 	array_ptr = EX_CONSTANT(opline->op1);
-	if (IS_CONST != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-		zend_bool is_empty;
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+		result = EX_VAR(opline->result.var);
+		ZVAL_COPY_VALUE(result, array_ptr);
+		if (IS_CONST != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+			Z_ADDREF_P(array_ptr);
+		}
+		Z_FE_POS_P(result) = 0;
 
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+		CHECK_EXCEPTION();
+		ZEND_VM_NEXT_OPCODE();
+	} else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			HashPosition pos = 0;
+			Bucket *p;
+
+			result = EX_VAR(opline->result.var);
+			ZVAL_COPY_VALUE(result, array_ptr);
+			if (IS_CONST != IS_TMP_VAR) {
+				Z_ADDREF_P(array_ptr);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			pos = 0;
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
 
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
 			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
-			if (UNEXPECTED(EG(exception) != NULL)) {
-				OBJ_RELEASE(&iter->std);
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
 
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
 				HANDLE_EXCEPTION();
 			}
-		}
 
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
 
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
+					HANDLE_EXCEPTION();
+				}
+			}
 
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			if (UNEXPECTED(EG(exception) != NULL)) {
+				OBJ_RELEASE(&iter->std);
 
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		zval *result = EX_VAR(opline->result.var);
+				HANDLE_EXCEPTION();
+			}
+			iter->index = -1; /* will be set to 0 before using next handler */
 
-		ZVAL_COPY_VALUE(result, array_ptr);
-		if (IS_CONST != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-			Z_ADDREF_P(array_ptr);
-		}
-		Z_FE_POS_P(result) = 0;
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-		CHECK_EXCEPTION();
-		ZEND_VM_NEXT_OPCODE();
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
+		}
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
+		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
 		ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 	}
@@ -3132,6 +3166,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
 
 	zval *array_ptr, *array_ref;
 	HashTable *fe_ht;
+	HashPosition pos = 0;
+	Bucket *p;
 
 	SAVE_OPLINE();
 
@@ -3144,70 +3180,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
 		array_ref = array_ptr = EX_CONSTANT(opline->op1);
 	}
 
-	if (IS_CONST != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-		zend_bool is_empty;
-
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-			if (IS_CONST == IS_VAR) {
-
-			} else {
-
-			}
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
-			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
-
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
-			if (UNEXPECTED(EG(exception) != NULL)) {
-				OBJ_RELEASE(&iter->std);
-				if (IS_CONST == IS_VAR) {
-
-				} else {
-
-				}
-				HANDLE_EXCEPTION();
-			}
-		}
-
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
-
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
-			if (IS_CONST == IS_VAR) {
-
-			} else {
-
-			}
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
-
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-		if (IS_CONST == IS_VAR) {
-
-		} else {
-
-		}
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		HashPosition pos = 0;
-		Bucket *p;
-
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
 		if (IS_CONST == IS_VAR || IS_CONST == IS_CV) {
 			if (array_ptr == array_ref) {
 				ZVAL_NEW_REF(array_ref, array_ref);
@@ -3219,14 +3192,12 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
 			array_ptr = EX_VAR(opline->result.var);
 			ZVAL_COPY_VALUE(array_ptr, array_ref);
 		}
-		if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-			if (IS_CONST == IS_CONST) {
-				zval_copy_ctor_func(array_ptr);
-			} else {
-				SEPARATE_ARRAY(array_ptr);
-			}
-			fe_ht = Z_ARRVAL_P(array_ptr);
+		if (IS_CONST == IS_CONST) {
+			zval_copy_ctor_func(array_ptr);
+		} else {
+			SEPARATE_ARRAY(array_ptr);
 		}
+		fe_ht = Z_ARRVAL_P(array_ptr);
 		while (1) {
 			if (pos >= fe_ht->nNumUsed) {
 
@@ -3234,12 +3205,9 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
 				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 			}
 			p = fe_ht->arData + pos;
-			if ((Z_TYPE(p->val) != IS_UNDEF &&
-			     (Z_TYPE(p->val) != IS_INDIRECT ||
-			      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-			    (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-			     !p->key ||
-			     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+			if (Z_TYPE(p->val) != IS_UNDEF &&
+			    (Z_TYPE(p->val) != IS_INDIRECT ||
+			     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
 				break;
 			}
 			pos++;
@@ -3249,6 +3217,101 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
 
 		CHECK_EXCEPTION();
 		ZEND_VM_NEXT_OPCODE();
+	} else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			if (IS_CONST == IS_VAR || IS_CONST == IS_CV) {
+				if (array_ptr == array_ref) {
+					ZVAL_NEW_REF(array_ref, array_ref);
+					array_ptr = Z_REFVAL_P(array_ref);
+				}
+				Z_ADDREF_P(array_ref);
+				ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+			} else {
+				array_ptr = EX_VAR(opline->result.var);
+				ZVAL_COPY_VALUE(array_ptr, array_ref);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
+
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
+			}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
+
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+				if (IS_CONST == IS_VAR) {
+
+				} else {
+
+				}
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
+				HANDLE_EXCEPTION();
+			}
+
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
+					if (IS_CONST == IS_VAR) {
+
+					} else {
+
+					}
+					HANDLE_EXCEPTION();
+				}
+			}
+
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+			if (UNEXPECTED(EG(exception) != NULL)) {
+				OBJ_RELEASE(&iter->std);
+				if (IS_CONST == IS_VAR) {
+
+				} else {
+
+				}
+				HANDLE_EXCEPTION();
+			}
+			iter->index = -1; /* will be set to 0 before using next handler */
+
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+			if (IS_CONST == IS_VAR) {
+
+			} else {
+
+			}
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
+		}
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -8993,69 +9056,103 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_R_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_A
 {
 	USE_OPLINE
 	zend_free_op free_op1;
-	zval *array_ptr;
+	zval *array_ptr, *result;
 	HashTable *fe_ht;
 
 	SAVE_OPLINE();
 
 	array_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
-	if (IS_TMP_VAR != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-		zend_bool is_empty;
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+		result = EX_VAR(opline->result.var);
+		ZVAL_COPY_VALUE(result, array_ptr);
+		if (IS_TMP_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+			Z_ADDREF_P(array_ptr);
+		}
+		Z_FE_POS_P(result) = 0;
 
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-			zval_ptr_dtor_nogc(free_op1);
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+		CHECK_EXCEPTION();
+		ZEND_VM_NEXT_OPCODE();
+	} else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			HashPosition pos = 0;
+			Bucket *p;
+
+			result = EX_VAR(opline->result.var);
+			ZVAL_COPY_VALUE(result, array_ptr);
+			if (IS_TMP_VAR != IS_TMP_VAR) {
+				Z_ADDREF_P(array_ptr);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			pos = 0;
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
+
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
 			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
-			if (UNEXPECTED(EG(exception) != NULL)) {
-				OBJ_RELEASE(&iter->std);
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
 				zval_ptr_dtor_nogc(free_op1);
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
 				HANDLE_EXCEPTION();
 			}
-		}
 
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
+					zval_ptr_dtor_nogc(free_op1);
+					HANDLE_EXCEPTION();
+				}
+			}
 
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
-			zval_ptr_dtor_nogc(free_op1);
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			if (UNEXPECTED(EG(exception) != NULL)) {
+				OBJ_RELEASE(&iter->std);
+				zval_ptr_dtor_nogc(free_op1);
+				HANDLE_EXCEPTION();
+			}
+			iter->index = -1; /* will be set to 0 before using next handler */
 
-		zval_ptr_dtor_nogc(free_op1);
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		zval *result = EX_VAR(opline->result.var);
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-		ZVAL_COPY_VALUE(result, array_ptr);
-		if (IS_TMP_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-			Z_ADDREF_P(array_ptr);
+			zval_ptr_dtor_nogc(free_op1);
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
 		}
-		Z_FE_POS_P(result) = 0;
-
-		CHECK_EXCEPTION();
-		ZEND_VM_NEXT_OPCODE();
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
+		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 		zval_ptr_dtor_nogc(free_op1);
 		ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 	}
@@ -9067,6 +9164,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
 	zend_free_op free_op1;
 	zval *array_ptr, *array_ref;
 	HashTable *fe_ht;
+	HashPosition pos = 0;
+	Bucket *p;
 
 	SAVE_OPLINE();
 
@@ -9079,70 +9178,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
 		array_ref = array_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
 	}
 
-	if (IS_TMP_VAR != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-		zend_bool is_empty;
-
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-			if (IS_TMP_VAR == IS_VAR) {
-
-			} else {
-				zval_ptr_dtor_nogc(free_op1);
-			}
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
-			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
-
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
-			if (UNEXPECTED(EG(exception) != NULL)) {
-				OBJ_RELEASE(&iter->std);
-				if (IS_TMP_VAR == IS_VAR) {
-
-				} else {
-					zval_ptr_dtor_nogc(free_op1);
-				}
-				HANDLE_EXCEPTION();
-			}
-		}
-
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
-
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
-			if (IS_TMP_VAR == IS_VAR) {
-
-			} else {
-				zval_ptr_dtor_nogc(free_op1);
-			}
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
-
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-		if (IS_TMP_VAR == IS_VAR) {
-
-		} else {
-			zval_ptr_dtor_nogc(free_op1);
-		}
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		HashPosition pos = 0;
-		Bucket *p;
-
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
 		if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) {
 			if (array_ptr == array_ref) {
 				ZVAL_NEW_REF(array_ref, array_ref);
@@ -9154,14 +9190,12 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
 			array_ptr = EX_VAR(opline->result.var);
 			ZVAL_COPY_VALUE(array_ptr, array_ref);
 		}
-		if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-			if (IS_TMP_VAR == IS_CONST) {
-				zval_copy_ctor_func(array_ptr);
-			} else {
-				SEPARATE_ARRAY(array_ptr);
-			}
-			fe_ht = Z_ARRVAL_P(array_ptr);
+		if (IS_TMP_VAR == IS_CONST) {
+			zval_copy_ctor_func(array_ptr);
+		} else {
+			SEPARATE_ARRAY(array_ptr);
 		}
+		fe_ht = Z_ARRVAL_P(array_ptr);
 		while (1) {
 			if (pos >= fe_ht->nNumUsed) {
 
@@ -9169,12 +9203,9 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
 				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 			}
 			p = fe_ht->arData + pos;
-			if ((Z_TYPE(p->val) != IS_UNDEF &&
-			     (Z_TYPE(p->val) != IS_INDIRECT ||
-			      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-			    (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-			     !p->key ||
-			     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+			if (Z_TYPE(p->val) != IS_UNDEF &&
+			    (Z_TYPE(p->val) != IS_INDIRECT ||
+			     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
 				break;
 			}
 			pos++;
@@ -9184,6 +9215,101 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
 
 		CHECK_EXCEPTION();
 		ZEND_VM_NEXT_OPCODE();
+	} else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			if (IS_TMP_VAR == IS_VAR || IS_TMP_VAR == IS_CV) {
+				if (array_ptr == array_ref) {
+					ZVAL_NEW_REF(array_ref, array_ref);
+					array_ptr = Z_REFVAL_P(array_ref);
+				}
+				Z_ADDREF_P(array_ref);
+				ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+			} else {
+				array_ptr = EX_VAR(opline->result.var);
+				ZVAL_COPY_VALUE(array_ptr, array_ref);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
+
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
+			}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
+
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+				if (IS_TMP_VAR == IS_VAR) {
+
+				} else {
+					zval_ptr_dtor_nogc(free_op1);
+				}
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
+				HANDLE_EXCEPTION();
+			}
+
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
+					if (IS_TMP_VAR == IS_VAR) {
+
+					} else {
+						zval_ptr_dtor_nogc(free_op1);
+					}
+					HANDLE_EXCEPTION();
+				}
+			}
+
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+			if (UNEXPECTED(EG(exception) != NULL)) {
+				OBJ_RELEASE(&iter->std);
+				if (IS_TMP_VAR == IS_VAR) {
+
+				} else {
+					zval_ptr_dtor_nogc(free_op1);
+				}
+				HANDLE_EXCEPTION();
+			}
+			iter->index = -1; /* will be set to 0 before using next handler */
+
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+			if (IS_TMP_VAR == IS_VAR) {
+
+			} else {
+				zval_ptr_dtor_nogc(free_op1);
+			}
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
+		}
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -11829,70 +11955,105 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_R_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
 {
 	USE_OPLINE
 	zend_free_op free_op1;
-	zval *array_ptr;
+	zval *array_ptr, *result;
 	HashTable *fe_ht;
 
 	SAVE_OPLINE();
 
 	array_ptr = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1);
-	if (IS_VAR != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-		zend_bool is_empty;
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+		result = EX_VAR(opline->result.var);
+		ZVAL_COPY_VALUE(result, array_ptr);
+		if (IS_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+			Z_ADDREF_P(array_ptr);
+		}
+		Z_FE_POS_P(result) = 0;
+
+		zval_ptr_dtor_nogc(free_op1);
+		CHECK_EXCEPTION();
+		ZEND_VM_NEXT_OPCODE();
+	} else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			HashPosition pos = 0;
+			Bucket *p;
+
+			result = EX_VAR(opline->result.var);
+			ZVAL_COPY_VALUE(result, array_ptr);
+			if (IS_VAR != IS_TMP_VAR) {
+				Z_ADDREF_P(array_ptr);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			pos = 0;
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
+					zval_ptr_dtor_nogc(free_op1);
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
+			}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
 			zval_ptr_dtor_nogc(free_op1);
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+				zval_ptr_dtor_nogc(free_op1);
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
+				HANDLE_EXCEPTION();
 			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
 
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
+					zval_ptr_dtor_nogc(free_op1);
+					HANDLE_EXCEPTION();
+				}
+			}
+
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
+
 			if (UNEXPECTED(EG(exception) != NULL)) {
 				OBJ_RELEASE(&iter->std);
 				zval_ptr_dtor_nogc(free_op1);
 				HANDLE_EXCEPTION();
 			}
-		}
+			iter->index = -1; /* will be set to 0 before using next handler */
 
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
 			zval_ptr_dtor_nogc(free_op1);
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
-
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-
-		zval_ptr_dtor_nogc(free_op1);
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		zval *result = EX_VAR(opline->result.var);
-
-		ZVAL_COPY_VALUE(result, array_ptr);
-		if (IS_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-			Z_ADDREF_P(array_ptr);
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
 		}
-		Z_FE_POS_P(result) = 0;
-
-		zval_ptr_dtor_nogc(free_op1);
-		CHECK_EXCEPTION();
-		ZEND_VM_NEXT_OPCODE();
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
+		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 		zval_ptr_dtor_nogc(free_op1);
 		ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 	}
@@ -11904,6 +12065,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
 	zend_free_op free_op1;
 	zval *array_ptr, *array_ref;
 	HashTable *fe_ht;
+	HashPosition pos = 0;
+	Bucket *p;
 
 	SAVE_OPLINE();
 
@@ -11916,28 +12079,114 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
 		array_ref = array_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
 	}
 
-	if (IS_VAR != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-		zend_bool is_empty;
-
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-			if (IS_VAR == IS_VAR) {
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+		if (IS_VAR == IS_VAR || IS_VAR == IS_CV) {
+			if (array_ptr == array_ref) {
+				ZVAL_NEW_REF(array_ref, array_ref);
+				array_ptr = Z_REFVAL_P(array_ref);
+			}
+			Z_ADDREF_P(array_ref);
+			ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+		} else {
+			array_ptr = EX_VAR(opline->result.var);
+			ZVAL_COPY_VALUE(array_ptr, array_ref);
+		}
+		if (IS_VAR == IS_CONST) {
+			zval_copy_ctor_func(array_ptr);
+		} else {
+			SEPARATE_ARRAY(array_ptr);
+		}
+		fe_ht = Z_ARRVAL_P(array_ptr);
+		while (1) {
+			if (pos >= fe_ht->nNumUsed) {
 				if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
-			} else {
-				zval_ptr_dtor_nogc(free_op1);
+				Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 			}
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+			p = fe_ht->arData + pos;
+			if (Z_TYPE(p->val) != IS_UNDEF &&
+			    (Z_TYPE(p->val) != IS_INDIRECT ||
+			     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
+				break;
 			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
+			pos++;
 		}
+		fe_ht->nInternalPointer = pos;
+		Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
+
+		if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+		CHECK_EXCEPTION();
+		ZEND_VM_NEXT_OPCODE();
+	} else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			if (IS_VAR == IS_VAR || IS_VAR == IS_CV) {
+				if (array_ptr == array_ref) {
+					ZVAL_NEW_REF(array_ref, array_ref);
+					array_ptr = Z_REFVAL_P(array_ref);
+				}
+				Z_ADDREF_P(array_ref);
+				ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+			} else {
+				array_ptr = EX_VAR(opline->result.var);
+				ZVAL_COPY_VALUE(array_ptr, array_ref);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
+					if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
+			}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
+
+			if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+				if (IS_VAR == IS_VAR) {
+					if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+				} else {
+					zval_ptr_dtor_nogc(free_op1);
+				}
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
+				HANDLE_EXCEPTION();
+			}
+
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
+					if (IS_VAR == IS_VAR) {
+						if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
+					} else {
+						zval_ptr_dtor_nogc(free_op1);
+					}
+					HANDLE_EXCEPTION();
+				}
+			}
+
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
 			if (UNEXPECTED(EG(exception) != NULL)) {
 				OBJ_RELEASE(&iter->std);
 				if (IS_VAR == IS_VAR) {
@@ -11947,81 +12196,23 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
 				}
 				HANDLE_EXCEPTION();
 			}
-		}
+			iter->index = -1; /* will be set to 0 before using next handler */
 
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
 			if (IS_VAR == IS_VAR) {
 				if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
 			} else {
 				zval_ptr_dtor_nogc(free_op1);
 			}
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
-
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-		if (IS_VAR == IS_VAR) {
-			if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
-		} else {
-			zval_ptr_dtor_nogc(free_op1);
-		}
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		HashPosition pos = 0;
-		Bucket *p;
-
-		if (IS_VAR == IS_VAR || IS_VAR == IS_CV) {
-			if (array_ptr == array_ref) {
-				ZVAL_NEW_REF(array_ref, array_ref);
-				array_ptr = Z_REFVAL_P(array_ref);
-			}
-			Z_ADDREF_P(array_ref);
-			ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
-		} else {
-			array_ptr = EX_VAR(opline->result.var);
-			ZVAL_COPY_VALUE(array_ptr, array_ref);
-		}
-		if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-			if (IS_VAR == IS_CONST) {
-				zval_copy_ctor_func(array_ptr);
-			} else {
-				SEPARATE_ARRAY(array_ptr);
-			}
-			fe_ht = Z_ARRVAL_P(array_ptr);
-		}
-		while (1) {
-			if (pos >= fe_ht->nNumUsed) {
-				if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
-				Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+			if (is_empty) {
 				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
 			}
-			p = fe_ht->arData + pos;
-			if ((Z_TYPE(p->val) != IS_UNDEF &&
-			     (Z_TYPE(p->val) != IS_INDIRECT ||
-			      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-			    (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-			     !p->key ||
-			     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
-				break;
-			}
-			pos++;
 		}
-		fe_ht->nInternalPointer = pos;
-		Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
-
-		if (free_op1) {zval_ptr_dtor_nogc(free_op1);};
-		CHECK_EXCEPTION();
-		ZEND_VM_NEXT_OPCODE();
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -12088,7 +12279,7 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
  			zend_object *zobj = Z_OBJ_P(array);
 
  			fe_ht = Z_OBJPROP_P(array);
-			pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+			pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
 			while (1) {
 				if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
 					/* reached end of iteration */
@@ -12127,7 +12318,24 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_R_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
 				}
 			}
 			ZVAL_COPY(EX_VAR(opline->result.var), value);
-			Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
+			while (1) {
+				pos++;
+				if (pos >= fe_ht->nNumUsed) {
+					pos = INVALID_IDX;
+					break;
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (Z_TYPE_P(array) != IS_OBJECT ||
+				     !p->key ||
+				     zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) {
+					break;
+				}
+			}
+			EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
+				fe_ht->nInternalPointer = pos;
 			ZEND_VM_INC_OPCODE();
 			ZEND_VM_NEXT_OPCODE();
 		} else {
@@ -24217,68 +24425,102 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_R_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_AR
 {
 	USE_OPLINE
 
-	zval *array_ptr;
+	zval *array_ptr, *result;
 	HashTable *fe_ht;
 
 	SAVE_OPLINE();
 
 	array_ptr = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var);
-	if (IS_CV != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
-		zend_bool is_empty;
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
+		result = EX_VAR(opline->result.var);
+		ZVAL_COPY_VALUE(result, array_ptr);
+		if (IS_CV != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
+			Z_ADDREF_P(array_ptr);
+		}
+		Z_FE_POS_P(result) = 0;
 
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+		CHECK_EXCEPTION();
+		ZEND_VM_NEXT_OPCODE();
+	} else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			HashPosition pos = 0;
+			Bucket *p;
+
+			result = EX_VAR(opline->result.var);
+			ZVAL_COPY_VALUE(result, array_ptr);
+			if (IS_CV != IS_TMP_VAR) {
+				Z_ADDREF_P(array_ptr);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			pos = 0;
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
 
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
 			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
 
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
-			if (UNEXPECTED(EG(exception) != NULL)) {
-				OBJ_RELEASE(&iter->std);
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
+			zend_bool is_empty;
 
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
 				HANDLE_EXCEPTION();
 			}
-		}
 
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
 
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
+					HANDLE_EXCEPTION();
+				}
+			}
 
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
 
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			if (UNEXPECTED(EG(exception) != NULL)) {
+				OBJ_RELEASE(&iter->std);
 
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		zval *result = EX_VAR(opline->result.var);
+				HANDLE_EXCEPTION();
+			}
+			iter->index = -1; /* will be set to 0 before using next handler */
 
-		ZVAL_COPY_VALUE(result, array_ptr);
-		if (IS_CV != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
-			Z_ADDREF_P(array_ptr);
-		}
-		Z_FE_POS_P(result) = 0;
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
-		CHECK_EXCEPTION();
-		ZEND_VM_NEXT_OPCODE();
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
+		}
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
+		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
 
 		ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 	}
@@ -24290,6 +24532,8 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
 
 	zval *array_ptr, *array_ref;
 	HashTable *fe_ht;
+	HashPosition pos = 0;
+	Bucket *p;
 
 	SAVE_OPLINE();
 
@@ -24302,70 +24546,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
 		array_ref = array_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
 	}
 
-	if (IS_CV != IS_CONST &&
-	    Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJCE_P(array_ptr)->get_iterator) {
-		zend_class_entry *ce = Z_OBJCE_P(array_ptr);
-		zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
-		zend_bool is_empty;
-
-		if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
-			if (IS_CV == IS_VAR) {
-
-			} else {
-
-			}
-			if (!EG(exception)) {
-				zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
-			}
-			zend_throw_exception_internal(NULL);
-			HANDLE_EXCEPTION();
-		}
-
-		iter->index = 0;
-		if (iter->funcs->rewind) {
-			iter->funcs->rewind(iter);
-			if (UNEXPECTED(EG(exception) != NULL)) {
-				OBJ_RELEASE(&iter->std);
-				if (IS_CV == IS_VAR) {
-
-				} else {
-
-				}
-				HANDLE_EXCEPTION();
-			}
-		}
-
-		is_empty = iter->funcs->valid(iter) != SUCCESS;
-
-		if (UNEXPECTED(EG(exception) != NULL)) {
-			OBJ_RELEASE(&iter->std);
-			if (IS_CV == IS_VAR) {
-
-			} else {
-
-			}
-			HANDLE_EXCEPTION();
-		}
-		iter->index = -1; /* will be set to 0 before using next handler */
-
-		ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
-		Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
-
-		if (IS_CV == IS_VAR) {
-
-		} else {
-
-		}
-		if (is_empty) {
-			ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
-		} else {
-			CHECK_EXCEPTION();
-			ZEND_VM_NEXT_OPCODE();
-		}
-	} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-		HashPosition pos = 0;
-		Bucket *p;
-
+	if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
 		if (IS_CV == IS_VAR || IS_CV == IS_CV) {
 			if (array_ptr == array_ref) {
 				ZVAL_NEW_REF(array_ref, array_ref);
@@ -24377,14 +24558,12 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
 			array_ptr = EX_VAR(opline->result.var);
 			ZVAL_COPY_VALUE(array_ptr, array_ref);
 		}
-		if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
-			if (IS_CV == IS_CONST) {
-				zval_copy_ctor_func(array_ptr);
-			} else {
-				SEPARATE_ARRAY(array_ptr);
-			}
-			fe_ht = Z_ARRVAL_P(array_ptr);
+		if (IS_CV == IS_CONST) {
+			zval_copy_ctor_func(array_ptr);
+		} else {
+			SEPARATE_ARRAY(array_ptr);
 		}
+		fe_ht = Z_ARRVAL_P(array_ptr);
 		while (1) {
 			if (pos >= fe_ht->nNumUsed) {
 
@@ -24392,12 +24571,9 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
 				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
 			}
 			p = fe_ht->arData + pos;
-			if ((Z_TYPE(p->val) != IS_UNDEF &&
-			     (Z_TYPE(p->val) != IS_INDIRECT ||
-			      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
-			    (Z_TYPE_P(array_ptr) != IS_OBJECT ||
-			     !p->key ||
-			     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+			if (Z_TYPE(p->val) != IS_UNDEF &&
+			    (Z_TYPE(p->val) != IS_INDIRECT ||
+			     Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
 				break;
 			}
 			pos++;
@@ -24407,6 +24583,101 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
 
 		CHECK_EXCEPTION();
 		ZEND_VM_NEXT_OPCODE();
+	} else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
+		if (!Z_OBJCE_P(array_ptr)->get_iterator) {
+			if (IS_CV == IS_VAR || IS_CV == IS_CV) {
+				if (array_ptr == array_ref) {
+					ZVAL_NEW_REF(array_ref, array_ref);
+					array_ptr = Z_REFVAL_P(array_ref);
+				}
+				Z_ADDREF_P(array_ref);
+				ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
+			} else {
+				array_ptr = EX_VAR(opline->result.var);
+				ZVAL_COPY_VALUE(array_ptr, array_ref);
+			}
+			fe_ht = Z_OBJPROP_P(array_ptr);
+			while (1) {
+				if (pos >= fe_ht->nNumUsed) {
+
+					Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+					ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+				}
+				p = fe_ht->arData + pos;
+				if ((Z_TYPE(p->val) != IS_UNDEF &&
+				     (Z_TYPE(p->val) != IS_INDIRECT ||
+				      Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
+				    (!p->key ||
+				     zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
+					break;
+				}
+				pos++;
+			}
+			fe_ht->nInternalPointer = pos;
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht);
+
+			CHECK_EXCEPTION();
+			ZEND_VM_NEXT_OPCODE();
+		} else {
+			zend_class_entry *ce = Z_OBJCE_P(array_ptr);
+			zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
+			zend_bool is_empty;
+
+			if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
+				if (IS_CV == IS_VAR) {
+
+				} else {
+
+				}
+				if (!EG(exception)) {
+					zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
+				}
+				zend_throw_exception_internal(NULL);
+				HANDLE_EXCEPTION();
+			}
+
+			iter->index = 0;
+			if (iter->funcs->rewind) {
+				iter->funcs->rewind(iter);
+				if (UNEXPECTED(EG(exception) != NULL)) {
+					OBJ_RELEASE(&iter->std);
+					if (IS_CV == IS_VAR) {
+
+					} else {
+
+					}
+					HANDLE_EXCEPTION();
+				}
+			}
+
+			is_empty = iter->funcs->valid(iter) != SUCCESS;
+
+			if (UNEXPECTED(EG(exception) != NULL)) {
+				OBJ_RELEASE(&iter->std);
+				if (IS_CV == IS_VAR) {
+
+				} else {
+
+				}
+				HANDLE_EXCEPTION();
+			}
+			iter->index = -1; /* will be set to 0 before using next handler */
+
+			ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
+			Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
+
+			if (IS_CV == IS_VAR) {
+
+			} else {
+
+			}
+			if (is_empty) {
+				ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+			} else {
+				CHECK_EXCEPTION();
+				ZEND_VM_NEXT_OPCODE();
+			}
+		}
 	} else {
 		zend_error(E_WARNING, "Invalid argument supplied for foreach()");
 		ZVAL_UNDEF(EX_VAR(opline->result.var));
@@ -33147,7 +33418,7 @@ static int ZEND_FASTCALL  ZEND_FE_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_A
 
 	SAVE_OPLINE();
 	var = EX_VAR(opline->op1.var);
-	if (Z_FE_ITER_P(var) != (uint32_t)-1) {
+	if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
 		zend_hash_iterator_del(Z_FE_ITER_P(var));
 	}
 	zval_ptr_dtor_nogc(var);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.