]> granicus.if.org Git - php/commitdiff
- Cleanup foreach statement
authorMarcus Boerger <helly@php.net>
Sat, 5 Feb 2005 14:01:59 +0000 (14:01 +0000)
committerMarcus Boerger <helly@php.net>
Sat, 5 Feb 2005 14:01:59 +0000 (14:01 +0000)
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index b893b12fb1d706cfe038649f2098168ef0cd0647..429d913e344787eb028f08ecacacc28c51b0b9af 100644 (file)
@@ -3343,7 +3343,7 @@ void zend_do_instanceof(znode *result, znode *expr, znode *class_znode, int type
 }
 
 
-void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable TSRMLS_DC)
+void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, znode *array, int variable TSRMLS_DC)
 {
        zend_op *opline;
        zend_bool is_variable;
@@ -3367,6 +3367,9 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack
                is_variable = 0;
        }
 
+       /* save the location of the beginning of the loop (array fetching) */
+       foreach_token->u.opline_num = get_next_op_number(CG(active_op_array));
+
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
        /* Preform array reset */
@@ -3392,10 +3395,17 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack
                }
                zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
        }
-       
-       /* save the location of the beginning of the loop (array fetching) */
-       opline->op2.u.opline_num = foreach_token->u.opline_num = get_next_op_number(CG(active_op_array));
+}
 
+
+void zend_do_foreach_cont(znode *foreach_token, znode *open_brackets_token, znode *as_token, znode *value, znode *key, znode *cont_token TSRMLS_DC)
+{
+       zend_op *opline;
+       znode result_value, result_key, dummy;
+       zend_bool assign_by_ref=0;
+
+       cont_token->u.opline_num = get_next_op_number(CG(active_op_array));
+       
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
        opline->opcode = ZEND_FE_FETCH;
        opline->result.op_type = IS_TMP_VAR;
@@ -3404,14 +3414,6 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack
        opline->extended_value = 0;
        SET_UNUSED(opline->op2);
        *as_token = opline->result;
-}
-
-
-void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC)
-{
-       zend_op *opline;
-       znode result_value, result_key, dummy;
-       zend_bool assign_by_ref=0;
 
        if (key->op_type != IS_UNUSED) {
                znode *tmp;
@@ -3422,7 +3424,7 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore
                value = tmp;
 
                /* Mark extended_value in case both key and value are being used */
-               CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_FETCH_WITH_KEY;
+               CG(active_op_array)->opcodes[cont_token->u.opline_num].extended_value |= ZEND_FE_FETCH_WITH_KEY;
        }
 
        if ((key->op_type != IS_UNUSED) && (key->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE)) {
@@ -3431,11 +3433,11 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore
        
        if (value->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE) {
                assign_by_ref = 1;
-               if (!CG(active_op_array)->opcodes[foreach_token->u.opline_num-1].extended_value) {
+               if (!CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value) {
                        zend_error(E_COMPILE_ERROR, "Cannot create references to elements of a temporary array expression");
                }
                /* Mark extended_value for assign-by-reference */
-               CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_FETCH_BYREF;
+               CG(active_op_array)->opcodes[cont_token->u.opline_num].extended_value |= ZEND_FE_FETCH_BYREF;
        }
 
        if (key->op_type != IS_UNUSED) {
@@ -3463,14 +3465,14 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore
                opline->extended_value = ZEND_FETCH_STANDARD; /* ignored in fetch_dim_tmp_var, but what the hell. */
                result_key = opline->result;
        } else {
-               result_value = CG(active_op_array)->opcodes[foreach_token->u.opline_num].result;
+               result_value = CG(active_op_array)->opcodes[cont_token->u.opline_num].result;
        }
 
        if (assign_by_ref) {
                if (key->op_type == IS_UNUSED) {
                        /* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */
-                       CG(active_op_array)->opcodes[foreach_token->u.opline_num].result.op_type = IS_VAR;
-                       zend_do_assign_ref(NULL, value, &CG(active_op_array)->opcodes[foreach_token->u.opline_num].result TSRMLS_CC);
+                       CG(active_op_array)->opcodes[cont_token->u.opline_num].result.op_type = IS_VAR;
+                       zend_do_assign_ref(NULL, value, &CG(active_op_array)->opcodes[cont_token->u.opline_num].result TSRMLS_CC);
                } else {
                        zend_do_assign_ref(NULL, value, &result_value TSRMLS_CC);
                }
@@ -3489,19 +3491,21 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore
 }
 
 
-void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token TSRMLS_DC)
+void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token, znode *cont_token TSRMLS_DC)
 {
        zend_op *container_ptr;
        zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 
        opline->opcode = ZEND_JMP;
-       opline->op1.u.opline_num = foreach_token->u.opline_num;
+       opline->op1.u.opline_num = cont_token->u.opline_num;
        SET_UNUSED(opline->op1);
        SET_UNUSED(opline->op2);
 
        CG(active_op_array)->opcodes[foreach_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
+       CG(active_op_array)->opcodes[foreach_token->u.opline_num+1].op2.u.opline_num = cont_token->u.opline_num;
+       CG(active_op_array)->opcodes[cont_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
 
-       do_end_loop(foreach_token->u.opline_num TSRMLS_CC);
+       do_end_loop(cont_token->u.opline_num TSRMLS_CC);
 
        zend_stack_top(&CG(foreach_copy_stack), (void **) &container_ptr);
        generate_free_foreach_copy(container_ptr TSRMLS_CC);
index 825ffca75899bdb23b45d176ed3055c525248c72..0b8c0cfaa6642e835b398a95de0cc02814d96923 100644 (file)
@@ -461,9 +461,9 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC
 
 void zend_do_instanceof(znode *result, znode *expr, znode *class_znode, int type TSRMLS_DC);
 
-void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable TSRMLS_DC);
-void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC);
-void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token TSRMLS_DC);
+void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, znode *array, int variable TSRMLS_DC);
+void zend_do_foreach_cont(znode *foreach_token, znode *open_brackets_token, znode *as_token, znode *value, znode *key, znode *cont_token TSRMLS_DC);
+void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token, znode *cont_token TSRMLS_DC);
 
 void zend_do_declare_begin(TSRMLS_D);
 void zend_do_declare_stmt(znode *var, znode *val TSRMLS_DC);
index 7dd066fb0afd7935ec79bc19f8bf74d4d5518ba6..8ccbc6dca9b5c493992ce54afb836dd7ace6d60b 100644 (file)
@@ -209,8 +209,14 @@ unticked_statement:
        |       expr ';'                                { zend_do_free(&$1 TSRMLS_CC); }
        |       T_USE use_filename ';'          { zend_error(E_COMPILE_ERROR,"use: Not yet supported. Please use include_once() or require_once()");  zval_dtor(&$2.u.constant); }
        |       T_UNSET '(' unset_variables ')' ';'
-       |       T_FOREACH '(' variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 1 TSRMLS_CC); } foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); }
-       |       T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 TSRMLS_CC); } w_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); }
+       |       T_FOREACH '(' variable T_AS foreach_variable foreach_optional_arg 
+               { zend_do_foreach_begin(&$1, &$2, &$3, 1 TSRMLS_CC); }
+               ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$5, &$6, &$8 TSRMLS_CC); }
+               foreach_statement { zend_do_foreach_end(&$1, &$2, &$8 TSRMLS_CC); }
+       |       T_FOREACH '(' expr_without_variable T_AS w_variable foreach_optional_arg 
+               { zend_do_foreach_begin(&$1, &$2, &$3, 0 TSRMLS_CC); }
+               ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$5, &$6, &$8 TSRMLS_CC); }
+               foreach_statement { zend_do_foreach_end(&$1, &$2, &$8 TSRMLS_CC); }
        |       T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); }
        |       ';'             /* empty statement */
        |       T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}'
index db0dc06569117ba134deaaad90b8153fbc51947f..eb1becd4d13c7cc0f28d6374f1d1cbec94075768 100644 (file)
@@ -2828,6 +2828,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
        HashTable *fe_ht;
        zend_object_iterator *iter = NULL;
        zend_class_entry *ce = NULL;
+       zend_bool is_empty = 0;
 
        if (opline->extended_value) {
                array_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
@@ -2889,20 +2890,26 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
                if (iter->funcs->rewind) {
                        iter->funcs->rewind(iter TSRMLS_CC);
                }
+               is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS;
        } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               /* probably redundant */
                zend_hash_internal_pointer_reset(fe_ht);
+               if (ce) {
+                       zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC);
+                       while (zend_hash_has_more_elements(fe_ht) == SUCCESS) {
+                               char *str_key;
+                               uint str_key_len;
+                               ulong int_key;
+                               if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING 
+                               && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) {
+                                       break;
+                               }
+                               zend_hash_move_forward(fe_ht);
+                       }
+               }
+               is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-
-               opline++;
-               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
-               if (opline->extended_value) {
-                       FREE_OP1_VAR_PTR();
-               } else {
-                       FREE_OP1_IF_VAR();
-               }
-               ZEND_VM_CONTINUE_JMP();
+               is_empty = 1;
        }
 
        if (opline->extended_value) {
@@ -2910,7 +2917,12 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
        } else {
                FREE_OP1_IF_VAR();
        }
-       ZEND_VM_NEXT_OPCODE();
+       if (is_empty) {
+               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
+               ZEND_VM_CONTINUE_JMP();
+       } else {
+               ZEND_VM_NEXT_OPCODE();
+       }
 }
 
 ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
@@ -2980,7 +2992,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
                                 * In case that ever happens we need an additional flag. */
                                iter->funcs->move_forward(iter TSRMLS_CC);
                        }
-                       if (!iter || iter->funcs->valid(iter TSRMLS_CC) == FAILURE) {
+                       if (!iter || (iter->index > 1 && iter->funcs->valid(iter TSRMLS_CC) == FAILURE)) {
                                /* reached end of iteration */
                                ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
                                ZEND_VM_CONTINUE_JMP();
index b2f075bbe103277fcf399c04a128e4e60f91504d..08e0611cc8f21066f84f5bb7b326d37fcd80e6e2 100644 (file)
@@ -1924,6 +1924,7 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        HashTable *fe_ht;
        zend_object_iterator *iter = NULL;
        zend_class_entry *ce = NULL;
+       zend_bool is_empty = 0;
 
        if (opline->extended_value) {
                array_ptr_ptr = _get_zval_ptr_ptr_const(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
@@ -1985,20 +1986,26 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (iter->funcs->rewind) {
                        iter->funcs->rewind(iter TSRMLS_CC);
                }
+               is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS;
        } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               /* probably redundant */
                zend_hash_internal_pointer_reset(fe_ht);
+               if (ce) {
+                       zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC);
+                       while (zend_hash_has_more_elements(fe_ht) == SUCCESS) {
+                               char *str_key;
+                               uint str_key_len;
+                               ulong int_key;
+                               if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING 
+                               && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) {
+                                       break;
+                               }
+                               zend_hash_move_forward(fe_ht);
+                       }
+               }
+               is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-
-               opline++;
-               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
-               if (opline->extended_value) {
-                       ;
-               } else {
-                       ;
-               }
-               ZEND_VM_CONTINUE_JMP();
+               is_empty = 1;
        }
 
        if (opline->extended_value) {
@@ -2006,7 +2013,12 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        } else {
                ;
        }
-       ZEND_VM_NEXT_OPCODE();
+       if (is_empty) {
+               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
+               ZEND_VM_CONTINUE_JMP();
+       } else {
+               ZEND_VM_NEXT_OPCODE();
+       }
 }
 
 static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -4343,6 +4355,7 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        HashTable *fe_ht;
        zend_object_iterator *iter = NULL;
        zend_class_entry *ce = NULL;
+       zend_bool is_empty = 0;
 
        if (opline->extended_value) {
                array_ptr_ptr = _get_zval_ptr_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
@@ -4404,20 +4417,26 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (iter->funcs->rewind) {
                        iter->funcs->rewind(iter TSRMLS_CC);
                }
+               is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS;
        } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               /* probably redundant */
                zend_hash_internal_pointer_reset(fe_ht);
+               if (ce) {
+                       zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC);
+                       while (zend_hash_has_more_elements(fe_ht) == SUCCESS) {
+                               char *str_key;
+                               uint str_key_len;
+                               ulong int_key;
+                               if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING 
+                               && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) {
+                                       break;
+                               }
+                               zend_hash_move_forward(fe_ht);
+                       }
+               }
+               is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-
-               opline++;
-               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
-               if (opline->extended_value) {
-                       ;
-               } else {
-                       ;
-               }
-               ZEND_VM_CONTINUE_JMP();
+               is_empty = 1;
        }
 
        if (opline->extended_value) {
@@ -4425,7 +4444,12 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        } else {
                ;
        }
-       ZEND_VM_NEXT_OPCODE();
+       if (is_empty) {
+               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
+               ZEND_VM_CONTINUE_JMP();
+       } else {
+               ZEND_VM_NEXT_OPCODE();
+       }
 }
 
 static int ZEND_JMP_NO_CTOR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -7424,6 +7448,7 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        HashTable *fe_ht;
        zend_object_iterator *iter = NULL;
        zend_class_entry *ce = NULL;
+       zend_bool is_empty = 0;
 
        if (opline->extended_value) {
                array_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
@@ -7485,20 +7510,26 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (iter->funcs->rewind) {
                        iter->funcs->rewind(iter TSRMLS_CC);
                }
+               is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS;
        } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               /* probably redundant */
                zend_hash_internal_pointer_reset(fe_ht);
+               if (ce) {
+                       zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC);
+                       while (zend_hash_has_more_elements(fe_ht) == SUCCESS) {
+                               char *str_key;
+                               uint str_key_len;
+                               ulong int_key;
+                               if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING 
+                               && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) {
+                                       break;
+                               }
+                               zend_hash_move_forward(fe_ht);
+                       }
+               }
+               is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-
-               opline++;
-               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
-               if (opline->extended_value) {
-                       if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
-               } else {
-                       if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
-               }
-               ZEND_VM_CONTINUE_JMP();
+               is_empty = 1;
        }
 
        if (opline->extended_value) {
@@ -7506,7 +7537,12 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        } else {
                if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
        }
-       ZEND_VM_NEXT_OPCODE();
+       if (is_empty) {
+               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
+               ZEND_VM_CONTINUE_JMP();
+       } else {
+               ZEND_VM_NEXT_OPCODE();
+       }
 }
 
 static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -7576,7 +7612,7 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                                 * In case that ever happens we need an additional flag. */
                                iter->funcs->move_forward(iter TSRMLS_CC);
                        }
-                       if (!iter || iter->funcs->valid(iter TSRMLS_CC) == FAILURE) {
+                       if (!iter || (iter->index > 1 && iter->funcs->valid(iter TSRMLS_CC) == FAILURE)) {
                                /* reached end of iteration */
                                ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
                                ZEND_VM_CONTINUE_JMP();
@@ -18203,6 +18239,7 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        HashTable *fe_ht;
        zend_object_iterator *iter = NULL;
        zend_class_entry *ce = NULL;
+       zend_bool is_empty = 0;
 
        if (opline->extended_value) {
                array_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), &free_op1, BP_VAR_R TSRMLS_CC);
@@ -18264,20 +18301,26 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (iter->funcs->rewind) {
                        iter->funcs->rewind(iter TSRMLS_CC);
                }
+               is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS;
        } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               /* probably redundant */
                zend_hash_internal_pointer_reset(fe_ht);
+               if (ce) {
+                       zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC);
+                       while (zend_hash_has_more_elements(fe_ht) == SUCCESS) {
+                               char *str_key;
+                               uint str_key_len;
+                               ulong int_key;
+                               if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING 
+                               && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) {
+                                       break;
+                               }
+                               zend_hash_move_forward(fe_ht);
+                       }
+               }
+               is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-
-               opline++;
-               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
-               if (opline->extended_value) {
-                       ;
-               } else {
-                       ;
-               }
-               ZEND_VM_CONTINUE_JMP();
+               is_empty = 1;
        }
 
        if (opline->extended_value) {
@@ -18285,7 +18328,12 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        } else {
                ;
        }
-       ZEND_VM_NEXT_OPCODE();
+       if (is_empty) {
+               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
+               ZEND_VM_CONTINUE_JMP();
+       } else {
+               ZEND_VM_NEXT_OPCODE();
+       }
 }
 
 static int ZEND_JMP_NO_CTOR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -30505,6 +30553,7 @@ static int ZEND_FE_RESET_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        HashTable *fe_ht;
        zend_object_iterator *iter = NULL;
        zend_class_entry *ce = NULL;
+       zend_bool is_empty = 0;
 
        if (opline->extended_value) {
                array_ptr_ptr = get_zval_ptr_ptr(&opline->op1, EX(Ts), &free_op1, BP_VAR_R);
@@ -30566,20 +30615,26 @@ static int ZEND_FE_RESET_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (iter->funcs->rewind) {
                        iter->funcs->rewind(iter TSRMLS_CC);
                }
+               is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS;
        } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
-               /* probably redundant */
                zend_hash_internal_pointer_reset(fe_ht);
+               if (ce) {
+                       zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC);
+                       while (zend_hash_has_more_elements(fe_ht) == SUCCESS) {
+                               char *str_key;
+                               uint str_key_len;
+                               ulong int_key;
+                               if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING 
+                               && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) {
+                                       break;
+                               }
+                               zend_hash_move_forward(fe_ht);
+                       }
+               }
+               is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
-
-               opline++;
-               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
-               if (opline->extended_value) {
-                       if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
-               } else {
-                       FREE_OP_IF_VAR(free_op1);
-               }
-               ZEND_VM_CONTINUE_JMP();
+               is_empty = 1;
        }
 
        if (opline->extended_value) {
@@ -30587,7 +30642,12 @@ static int ZEND_FE_RESET_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        } else {
                FREE_OP_IF_VAR(free_op1);
        }
-       ZEND_VM_NEXT_OPCODE();
+       if (is_empty) {
+               ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
+               ZEND_VM_CONTINUE_JMP();
+       } else {
+               ZEND_VM_NEXT_OPCODE();
+       }
 }
 
 static int ZEND_FE_FETCH_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -30657,7 +30717,7 @@ static int ZEND_FE_FETCH_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                                 * In case that ever happens we need an additional flag. */
                                iter->funcs->move_forward(iter TSRMLS_CC);
                        }
-                       if (!iter || iter->funcs->valid(iter TSRMLS_CC) == FAILURE) {
+                       if (!iter || (iter->index > 1 && iter->funcs->valid(iter TSRMLS_CC) == FAILURE)) {
                                /* reached end of iteration */
                                ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num);
                                ZEND_VM_CONTINUE_JMP();