- Disallow foreach($v as &$ref) when $v is an object that implements

interface Iterator. The signature of Iterator::current() doesn't allow
  that. Maybe ppl also want IteratorByReference or similar. Unfortunatley
  this comes with an API change but there is no easier way.
This commit is contained in:
Marcus Boerger 2006-02-05 23:26:55 +00:00
parent a6e8746bbe
commit c8d78028b5
9 changed files with 43 additions and 29 deletions

View File

@ -357,7 +357,7 @@ struct _zend_class_entry {
/* handlers */
zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object TSRMLS_DC);
zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
/* serializer callbacks */

View File

@ -3757,7 +3757,7 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno
opline->result.u.var = get_temporary_variable(CG(active_op_array));
opline->op1 = *array;
SET_UNUSED(opline->op2);
opline->extended_value = is_variable;
opline->extended_value = is_variable ? ZEND_FE_RESET_VARIABLE : 0;
*open_brackets_token = opline->result;
{
@ -3830,6 +3830,7 @@ void zend_do_foreach_cont(znode *foreach_token, znode *as_token, znode *value, z
}
/* Mark extended_value for assign-by-reference */
opline->extended_value |= ZEND_FE_FETCH_BYREF;
CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_RESET_REFERENCE;
}
value_node = opline->result;

View File

@ -661,6 +661,9 @@ int zendlex(znode *zendlval TSRMLS_DC);
#define ZEND_FE_FETCH_BYREF 1
#define ZEND_FE_FETCH_WITH_KEY 2
#define ZEND_FE_RESET_VARIABLE 1
#define ZEND_FE_RESET_REFERENCE 2
#define ZEND_MEMBER_FUNC_CALL 1<<0
#define ZEND_ARG_SEND_BY_REF (1<<0)

View File

@ -34,6 +34,7 @@
#include "zend_fast_cache.h"
#include "zend_ini.h"
#include "zend_exceptions.h"
#include "zend_interfaces.h"
#include "zend_vm.h"
#include "zend_unicode.h"

View File

@ -270,9 +270,15 @@ zend_object_iterator_funcs zend_interface_iterator_funcs_iterator = {
};
/* {{{ zend_user_it_get_iterator */
static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
{
zend_user_iterator *iterator = emalloc(sizeof(zend_user_iterator));
zend_user_iterator *iterator;
if (by_ref) {
zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
}
iterator = emalloc(sizeof(zend_user_iterator));
object->refcount++;
iterator->it.data = (void*)object;
@ -284,7 +290,7 @@ static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zva
/* }}} */
/* {{{ zend_user_it_get_new_iterator */
static zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
{
zval *iterator = zend_user_it_new_iterator(ce, object TSRMLS_CC);
zend_object_iterator *new_iterator;
@ -302,7 +308,11 @@ static zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce,
}
return NULL;
}
new_iterator = ce_it->get_iterator(ce_it, iterator TSRMLS_CC);
if (by_ref && ce_it && instanceof_function(ce_it, zend_ce_iterator TSRMLS_CC)) {
zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
}
new_iterator = ce_it->get_iterator(ce_it, iterator, by_ref TSRMLS_CC);
zval_ptr_dtor(&iterator);
return new_iterator;
}

View File

@ -49,6 +49,8 @@ ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend
#define zend_call_method_with_2_params(obj, obj_ce, fn_proxy, function_name, retval, arg1, arg2) \
zend_call_method(obj, obj_ce, fn_proxy, function_name, sizeof(function_name)-1, retval, 2, arg1, arg2 TSRMLS_CC)
ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
ZEND_API void zend_register_interfaces(TSRMLS_D);
END_EXTERN_C()

View File

@ -57,11 +57,8 @@ struct _zend_object_iterator {
ulong index; /* private to fe_reset/fe_fetch opcodes */
};
typedef zval *(*zend_object_new_iterator_t)(zend_class_entry *ce, zval *object TSRMLS_DC);
typedef struct _zend_class_iterator_funcs {
zend_object_iterator_funcs *funcs;
zend_object_new_iterator_t new_iterator;
union _zend_function *zf_new_iterator;
union _zend_function *zf_valid;
union _zend_function *zf_current;

View File

@ -3041,7 +3041,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
zend_class_entry *ce = NULL;
zend_bool is_empty = 0;
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
array_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) {
ALLOC_INIT_ZVAL(array_ptr);
@ -3078,12 +3078,12 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
}
if (ce && ce->get_iterator) {
iter = ce->get_iterator(ce, array_ptr TSRMLS_CC);
iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC);
if (iter && !EG(exception)) {
array_ptr = zend_iterator_wrap(iter TSRMLS_CC);
} else {
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
FREE_OP1_VAR_PTR();
} else {
FREE_OP1_IF_VAR();
@ -3140,7 +3140,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
is_empty = 1;
}
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
FREE_OP1_VAR_PTR();
} else {
FREE_OP1_IF_VAR();

View File

@ -1980,7 +1980,7 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_class_entry *ce = NULL;
zend_bool is_empty = 0;
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
array_ptr_ptr = NULL;
if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) {
ALLOC_INIT_ZVAL(array_ptr);
@ -2017,12 +2017,12 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
if (ce && ce->get_iterator) {
iter = ce->get_iterator(ce, array_ptr TSRMLS_CC);
iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC);
if (iter && !EG(exception)) {
array_ptr = zend_iterator_wrap(iter TSRMLS_CC);
} else {
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
} else {
@ -2079,7 +2079,7 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
is_empty = 1;
}
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
} else {
@ -4478,7 +4478,7 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_class_entry *ce = NULL;
zend_bool is_empty = 0;
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
array_ptr_ptr = NULL;
if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) {
ALLOC_INIT_ZVAL(array_ptr);
@ -4515,12 +4515,12 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
if (ce && ce->get_iterator) {
iter = ce->get_iterator(ce, array_ptr TSRMLS_CC);
iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC);
if (iter && !EG(exception)) {
array_ptr = zend_iterator_wrap(iter TSRMLS_CC);
} else {
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
} else {
@ -4577,7 +4577,7 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
is_empty = 1;
}
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
} else {
@ -7573,7 +7573,7 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_class_entry *ce = NULL;
zend_bool is_empty = 0;
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
array_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) {
ALLOC_INIT_ZVAL(array_ptr);
@ -7610,12 +7610,12 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
if (ce && ce->get_iterator) {
iter = ce->get_iterator(ce, array_ptr TSRMLS_CC);
iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC);
if (iter && !EG(exception)) {
array_ptr = zend_iterator_wrap(iter TSRMLS_CC);
} else {
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
} else {
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
@ -7672,7 +7672,7 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
is_empty = 1;
}
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
} else {
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
@ -20213,7 +20213,7 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_class_entry *ce = NULL;
zend_bool is_empty = 0;
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
array_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC);
if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) {
ALLOC_INIT_ZVAL(array_ptr);
@ -20250,12 +20250,12 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
if (ce && ce->get_iterator) {
iter = ce->get_iterator(ce, array_ptr TSRMLS_CC);
iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC);
if (iter && !EG(exception)) {
array_ptr = zend_iterator_wrap(iter TSRMLS_CC);
} else {
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
} else {
@ -20312,7 +20312,7 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
is_empty = 1;
}
if (opline->extended_value) {
if (opline->extended_value & ZEND_FE_RESET_VARIABLE) {
} else {