mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
Change "foreach" statement behavior (this is just a PoC yet)
- "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
This commit is contained in:
parent
638d0cb753
commit
4638f7b914
@ -23,4 +23,4 @@ var_dump(key($arr["v"]));
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
NULL
|
||||
int(0)
|
||||
|
@ -23,4 +23,4 @@ int(0)
|
||||
int(0)
|
||||
int(1)
|
||||
int(2)
|
||||
NULL
|
||||
int(0)
|
||||
|
@ -3396,30 +3396,22 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
|
||||
}
|
||||
|
||||
opnum_reset = get_next_op_number(CG(active_op_array));
|
||||
opline = zend_emit_op(&reset_node, ZEND_FE_RESET, &expr_node, NULL);
|
||||
if (by_ref && is_variable) {
|
||||
opline->extended_value = ZEND_FE_FETCH_BYREF;
|
||||
}
|
||||
opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
|
||||
|
||||
zend_stack_push(&CG(loop_var_stack), &reset_node);
|
||||
|
||||
opnum_fetch = get_next_op_number(CG(active_op_array));
|
||||
opline = zend_emit_op(&value_node, ZEND_FE_FETCH, &reset_node, NULL);
|
||||
if (by_ref) {
|
||||
opline->extended_value |= ZEND_FE_FETCH_BYREF;
|
||||
}
|
||||
opline = zend_emit_op(&value_node, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
|
||||
if (key_ast) {
|
||||
opline->extended_value |= ZEND_FE_FETCH_WITH_KEY;
|
||||
opline->extended_value = 1;
|
||||
}
|
||||
|
||||
opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL);
|
||||
|
||||
/* Allocate enough space to keep HashPointer on VM stack */
|
||||
if (by_ref) {
|
||||
/* Allocate temporary variable to keep HashTable value */
|
||||
opline->op1_type = IS_TMP_VAR;
|
||||
opline->op1.var = get_temporary_variable(CG(active_op_array));
|
||||
if (sizeof(HashPointer) > sizeof(zval)) {
|
||||
/* Make sure 1 zval is enough for HashPointer (2 must be enough) */
|
||||
get_temporary_variable(CG(active_op_array));
|
||||
}
|
||||
|
||||
if (key_ast) {
|
||||
|
@ -828,9 +828,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv);
|
||||
|
||||
#define ZEND_FETCH_ARG_MASK 0x000fffff
|
||||
|
||||
#define ZEND_FE_FETCH_BYREF 1
|
||||
#define ZEND_FE_FETCH_WITH_KEY 2
|
||||
|
||||
#define EXT_TYPE_FREE_ON_RETURN (1<<2)
|
||||
|
||||
#define ZEND_MEMBER_FUNC_CALL 1<<0
|
||||
|
@ -171,13 +171,6 @@ ZEND_API zval *zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos);
|
||||
ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
|
||||
ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
|
||||
|
||||
typedef struct _HashPointer {
|
||||
HashPosition pos;
|
||||
HashTable *ht;
|
||||
zend_ulong h;
|
||||
zend_string *key;
|
||||
} HashPointer;
|
||||
|
||||
#define zend_hash_has_more_elements(ht) \
|
||||
zend_hash_has_more_elements_ex(ht, &(ht)->nInternalPointer)
|
||||
#define zend_hash_move_forward(ht) \
|
||||
|
@ -766,8 +766,10 @@ ZEND_API int pass_two(zend_op_array *op_array)
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_NEW:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
|
||||
break;
|
||||
case ZEND_VERIFY_RETURN_TYPE:
|
||||
|
@ -128,6 +128,7 @@ struct _zval_struct {
|
||||
uint32_t cache_slot; /* literal cache slot */
|
||||
uint32_t lineno; /* line number (for ast nodes) */
|
||||
uint32_t num_args; /* arguments number for EX(This) */
|
||||
uint32_t fe_pos; /* foreach position */
|
||||
} u2;
|
||||
};
|
||||
|
||||
@ -261,6 +262,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
|
||||
#define Z_CACHE_SLOT(zval) (zval).u2.cache_slot
|
||||
#define Z_CACHE_SLOT_P(zval_p) Z_CACHE_SLOT(*(zval_p))
|
||||
|
||||
#define Z_FE_POS(zval) (zval).u2.fe_pos
|
||||
#define Z_FE_POS_P(zval_p) Z_FE_POS(*(zval_p))
|
||||
|
||||
#define Z_COUNTED(zval) (zval).value.counted
|
||||
#define Z_COUNTED_P(zval_p) Z_COUNTED(*(zval_p))
|
||||
|
||||
|
@ -4620,245 +4620,200 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|CV, CONST|TMPVAR|CV)
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
|
||||
ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *array_ptr, *array_ref, iterator, tmp;
|
||||
zval *array_ptr;
|
||||
HashTable *fe_ht;
|
||||
zend_object_iterator *iter = NULL;
|
||||
zend_class_entry *ce = NULL;
|
||||
zend_bool is_empty = 0;
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) &&
|
||||
(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
|
||||
array_ptr = array_ref = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
|
||||
array_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
ZVAL_DEREF(array_ptr);
|
||||
if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
|
||||
SEPARATE_ARRAY(array_ptr);
|
||||
if (!Z_ISREF_P(array_ref)) {
|
||||
ZVAL_NEW_REF(array_ref, array_ref);
|
||||
array_ptr = Z_REFVAL_P(array_ref);
|
||||
}
|
||||
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
|
||||
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
|
||||
ce = Z_OBJCE_P(array_ptr);
|
||||
if (ce->get_iterator == NULL) {
|
||||
Z_ADDREF_P(array_ptr);
|
||||
}
|
||||
array_ref = array_ptr;
|
||||
} else {
|
||||
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
|
||||
}
|
||||
} else {
|
||||
array_ptr = array_ref = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
if (OP1_TYPE & (IS_VAR|IS_CV)) {
|
||||
ZVAL_DEREF(array_ptr);
|
||||
}
|
||||
if (OP1_TYPE == IS_TMP_VAR) {
|
||||
ZVAL_COPY_VALUE(&tmp, array_ptr);
|
||||
if (Z_OPT_IMMUTABLE_P(&tmp)) {
|
||||
zval_copy_ctor_func(&tmp);
|
||||
}
|
||||
array_ref = array_ptr = &tmp;
|
||||
if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
|
||||
ce = Z_OBJCE_P(array_ptr);
|
||||
if (ce && ce->get_iterator) {
|
||||
Z_DELREF_P(array_ref);
|
||||
}
|
||||
}
|
||||
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
|
||||
ce = Z_OBJCE_P(array_ptr);
|
||||
if (!ce->get_iterator) {
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
Z_ADDREF_P(array_ref);
|
||||
}
|
||||
}
|
||||
} else if (Z_IMMUTABLE_P(array_ref)) {
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
zval_copy_ctor_func(array_ref);
|
||||
Z_ADDREF_P(array_ref);
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(&tmp, array_ref);
|
||||
zval_copy_ctor_func(&tmp);
|
||||
array_ptr = array_ref = &tmp;
|
||||
}
|
||||
} else if (Z_REFCOUNTED_P(array_ref)) {
|
||||
if (OP1_TYPE == IS_CONST ||
|
||||
(OP1_TYPE == IS_CV &&
|
||||
!Z_ISREF_P(array_ref) &&
|
||||
Z_REFCOUNT_P(array_ref) > 1) ||
|
||||
(OP1_TYPE == IS_VAR &&
|
||||
!Z_ISREF_P(array_ref) &&
|
||||
Z_REFCOUNT_P(array_ref) > 2)) {
|
||||
if (OP1_TYPE == IS_VAR) {
|
||||
Z_DELREF_P(array_ref);
|
||||
}
|
||||
ZVAL_DUP(&tmp, array_ref);
|
||||
array_ptr = array_ref = &tmp;
|
||||
} else if (OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) {
|
||||
if (Z_ISREF_P(array_ref) && Z_REFCOUNT_P(array_ref) == 1) {
|
||||
ZVAL_UNREF(array_ref);
|
||||
array_ptr = array_ref;
|
||||
}
|
||||
if (Z_IMMUTABLE_P(array_ptr)) {
|
||||
zval_copy_ctor_func(array_ptr);
|
||||
} else if (Z_ISREF_P(array_ref) &&
|
||||
Z_COPYABLE_P(array_ptr) &&
|
||||
Z_REFCOUNT_P(array_ptr) > 1) {
|
||||
Z_DELREF_P(array_ptr);
|
||||
zval_copy_ctor_func(array_ptr);
|
||||
}
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
Z_ADDREF_P(array_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 (ce && ce->get_iterator) {
|
||||
iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_FETCH_BYREF);
|
||||
|
||||
if (OP1_TYPE == IS_VAR && !(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
|
||||
if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
|
||||
FREE_OP1_IF_VAR();
|
||||
}
|
||||
if (iter && EXPECTED(EG(exception) == NULL)) {
|
||||
ZVAL_OBJ(&iterator, &iter->std);
|
||||
array_ptr = array_ref = &iterator;
|
||||
} else {
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
|
||||
|
||||
if (iter) {
|
||||
iter->index = 0;
|
||||
if (iter->funcs->rewind) {
|
||||
iter->funcs->rewind(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
FREE_OP1_IF_VAR();
|
||||
OBJ_RELEASE(&iter->std);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
|
||||
is_empty = iter->funcs->valid(iter) != SUCCESS;
|
||||
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
FREE_OP1_IF_VAR();
|
||||
OBJ_RELEASE(&iter->std);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
iter->index = -1; /* will be set to 0 before using next handler */
|
||||
} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
|
||||
HashPointer *ptr = (HashPointer*)EX_VAR((opline+2)->op1.var);
|
||||
HashPosition pos = 0;
|
||||
Bucket *p;
|
||||
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
is_empty = 1;
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
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)) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
if (!ce ||
|
||||
!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
fe_ht->nInternalPointer = pos;
|
||||
ptr->pos = pos;
|
||||
ptr->ht = fe_ht;
|
||||
ptr->h = fe_ht->arData[pos].h;
|
||||
ptr->key = fe_ht->arData[pos].key;
|
||||
is_empty = 0;
|
||||
} else {
|
||||
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
|
||||
is_empty = 1;
|
||||
}
|
||||
ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
|
||||
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
FREE_OP1_IF_VAR();
|
||||
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) {
|
||||
if (OP1_TYPE != IS_TMP_VAR) {
|
||||
if (Z_REFCOUNTED_P(array_ptr)) {
|
||||
Z_ADDREF_P(array_ptr);
|
||||
}
|
||||
}
|
||||
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ptr);
|
||||
Z_FE_POS_P(EX_VAR(opline->result.var)) = 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));
|
||||
FREE_OP1();
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *array, *array_ref;
|
||||
zval *value;
|
||||
zval *array_ptr, *array_ref;
|
||||
HashTable *fe_ht;
|
||||
HashPointer *ptr;
|
||||
HashPosition pos;
|
||||
Bucket *p;
|
||||
|
||||
array = array_ref = EX_VAR(opline->op1.var);
|
||||
if (Z_ISREF_P(array)) {
|
||||
array = Z_REFVAL_P(array);
|
||||
// TODO: referenced value might be changed to different array ???
|
||||
if (Z_IMMUTABLE_P(array)) {
|
||||
zval_copy_ctor_func(array);
|
||||
}
|
||||
}
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
|
||||
array_ref = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
|
||||
ZVAL_MAKE_REF(array_ref);
|
||||
array_ptr = Z_REFVAL_P(array_ref);
|
||||
if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
|
||||
SEPARATE_ARRAY(array_ptr);
|
||||
}
|
||||
} else {
|
||||
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))) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
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)) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
OBJ_RELEASE(&iter->std);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
|
||||
is_empty = iter->funcs->valid(iter) != SUCCESS;
|
||||
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
OBJ_RELEASE(&iter->std);
|
||||
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_POS_P(EX_VAR(opline->result.var)) = INVALID_IDX;
|
||||
ZVAL_PTR(EX_VAR((opline+2)->op1.var), NULL);
|
||||
|
||||
FREE_OP1_VAR_PTR();
|
||||
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 (OP1_TYPE != IS_TMP_VAR) {
|
||||
if (Z_REFCOUNTED_P(array_ref)) {
|
||||
Z_ADDREF_P(array_ref);
|
||||
}
|
||||
}
|
||||
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
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)) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->result.var)) = fe_ht->nInternalPointer = pos;
|
||||
ZVAL_PTR(EX_VAR((opline+2)->op1.var), fe_ht);
|
||||
|
||||
FREE_OP1_VAR_PTR();
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
|
||||
ZVAL_UNDEF(EX_VAR(opline->result.var));
|
||||
FREE_OP1_VAR_PTR();
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *array;
|
||||
zval *value;
|
||||
HashTable *fe_ht;
|
||||
HashPosition pos;
|
||||
Bucket *p;
|
||||
|
||||
array = EX_VAR(opline->op1.var);
|
||||
SAVE_OPLINE();
|
||||
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
|
||||
fe_ht = Z_ARRVAL_P(array);
|
||||
ptr = (HashPointer*)EX_VAR((opline+1)->op1.var);
|
||||
pos = ptr->pos;
|
||||
if (UNEXPECTED(pos == INVALID_IDX)) {
|
||||
/* reached end of iteration */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else if (UNEXPECTED(ptr->ht != fe_ht)) {
|
||||
ptr->ht = fe_ht;
|
||||
pos = 0;
|
||||
} else if (UNEXPECTED(fe_ht->nInternalPointer != ptr->pos)) {
|
||||
if (fe_ht->u.flags & HASH_FLAG_PACKED) {
|
||||
pos = ptr->h;
|
||||
} else {
|
||||
pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
|
||||
while (1) {
|
||||
if (pos == INVALID_IDX) {
|
||||
pos = fe_ht->nInternalPointer;
|
||||
break;
|
||||
} else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
|
||||
break;
|
||||
}
|
||||
pos = Z_NEXT(fe_ht->arData[pos].val);
|
||||
}
|
||||
}
|
||||
}
|
||||
pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
|
||||
while (1) {
|
||||
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
|
||||
/* reached end of iteration */
|
||||
@ -4866,46 +4821,27 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
value = &p->val;
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
} else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
|
||||
} else if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
value = Z_INDIRECT_P(value);
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
} else {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
break;
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
|
||||
if (opline->extended_value) {
|
||||
if (!p->key) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
do {
|
||||
pos++;
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
fe_ht->nInternalPointer = ptr->pos = INVALID_IDX;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
} while (Z_TYPE(p->val) == IS_UNDEF ||
|
||||
(Z_TYPE(p->val) == IS_INDIRECT &&
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF));
|
||||
fe_ht->nInternalPointer = ptr->pos = pos;
|
||||
ptr->h = fe_ht->arData[pos].h;
|
||||
ptr->key = fe_ht->arData[pos].key;
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
|
||||
@ -4916,30 +4852,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
zend_object *zobj = Z_OBJ_P(array);
|
||||
|
||||
fe_ht = Z_OBJPROP_P(array);
|
||||
ptr = (HashPointer*)EX_VAR((opline+1)->op1.var);
|
||||
pos = ptr->pos;
|
||||
if (pos == INVALID_IDX) {
|
||||
/* reached end of iteration */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else if (UNEXPECTED(ptr->ht != fe_ht)) {
|
||||
ptr->ht = fe_ht;
|
||||
pos = 0;
|
||||
} else if (UNEXPECTED(fe_ht->nInternalPointer != ptr->pos)) {
|
||||
if (fe_ht->u.flags & HASH_FLAG_PACKED) {
|
||||
pos = ptr->h;
|
||||
} else {
|
||||
pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
|
||||
while (1) {
|
||||
if (pos == INVALID_IDX) {
|
||||
pos = fe_ht->nInternalPointer;
|
||||
break;
|
||||
} else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
|
||||
break;
|
||||
}
|
||||
pos = Z_NEXT(fe_ht->arData[pos].val);
|
||||
}
|
||||
}
|
||||
}
|
||||
pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
|
||||
while (1) {
|
||||
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
|
||||
/* reached end of iteration */
|
||||
@ -4948,25 +4861,26 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
|
||||
p = fe_ht->arData + pos;
|
||||
value = &p->val;
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
} else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
|
||||
} else if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
value = Z_INDIRECT_P(value);
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(!p->key)) {
|
||||
if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
}
|
||||
if (!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS) {
|
||||
break;
|
||||
} else if (zend_check_property_access(zobj, p->key) == SUCCESS) {
|
||||
if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
|
||||
if (p->key->val[0]) {
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (opline->extended_value) {
|
||||
if (UNEXPECTED(!p->key)) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else if (p->key->val[0]) {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
} else {
|
||||
const char *class_name, *prop_name;
|
||||
@ -4976,33 +4890,8 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
} else {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
}
|
||||
do {
|
||||
pos++;
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
fe_ht->nInternalPointer = ptr->pos = INVALID_IDX;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
} while (Z_TYPE(p->val) == IS_UNDEF ||
|
||||
(Z_TYPE(p->val) == IS_INDIRECT &&
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF) ||
|
||||
(EXPECTED(p->key != NULL) &&
|
||||
zend_check_property_access(zobj, p->key) == FAILURE));
|
||||
fe_ht->nInternalPointer = ptr->pos = pos;
|
||||
ptr->h = fe_ht->arData[pos].h;
|
||||
ptr->key = fe_ht->arData[pos].key;
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
@ -5012,7 +4901,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);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
@ -5020,32 +4909,236 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
|
||||
/* reached end of iteration */
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
value = iter->funcs->get_current_data(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
if (!value) {
|
||||
/* failure in get_current_data */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
} else {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
|
||||
if (opline->extended_value) {
|
||||
if (iter->funcs->get_current_key) {
|
||||
iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} else {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
|
||||
}
|
||||
}
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
} else {
|
||||
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *array;
|
||||
zval *value;
|
||||
HashTable *fe_ht;
|
||||
HashPosition pos;
|
||||
Bucket *p;
|
||||
|
||||
array = EX_VAR(opline->op1.var);
|
||||
SAVE_OPLINE();
|
||||
|
||||
ZVAL_DEREF(array);
|
||||
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
|
||||
fe_ht = Z_ARRVAL_P(array);
|
||||
pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
|
||||
if (UNEXPECTED(pos == INVALID_IDX)) {
|
||||
/* reached end of iteration */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else {
|
||||
if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
|
||||
pos = fe_ht->nInternalPointer;
|
||||
}
|
||||
SEPARATE_ARRAY(array);
|
||||
fe_ht = Z_ARRVAL_P(array);
|
||||
Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
|
||||
}
|
||||
//??? if (pos != fe_ht->nInternalPointer) {
|
||||
//??? //...
|
||||
//??? }
|
||||
while (1) {
|
||||
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
|
||||
/* reached end of iteration */
|
||||
fe_ht->nInternalPointer = INVALID_IDX;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
value = &p->val;
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
} else if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
value = Z_INDIRECT_P(value);
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (opline->extended_value) {
|
||||
if (!p->key) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
}
|
||||
}
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
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)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
|
||||
zend_object_iterator *iter;
|
||||
|
||||
if ((iter = zend_iterator_unwrap(array)) == NULL) {
|
||||
/* plain object */
|
||||
zend_object *zobj = Z_OBJ_P(array);
|
||||
|
||||
fe_ht = Z_OBJPROP_P(array);
|
||||
pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
|
||||
if (UNEXPECTED(pos == INVALID_IDX)) {
|
||||
/* reached end of iteration */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else {
|
||||
if (Z_PTR_P(EX_VAR((opline+1)->op1.var)) != fe_ht) {
|
||||
pos = fe_ht->nInternalPointer;
|
||||
}
|
||||
Z_PTR_P(EX_VAR((opline+1)->op1.var)) = fe_ht;
|
||||
}
|
||||
//??? if (pos != fe_ht->nInternalPointer) {
|
||||
//???
|
||||
//??? }
|
||||
while (1) {
|
||||
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
|
||||
/* reached end of iteration */
|
||||
fe_ht->nInternalPointer = INVALID_IDX;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
|
||||
p = fe_ht->arData + pos;
|
||||
value = &p->val;
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
} else if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
value = Z_INDIRECT_P(value);
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (opline->extended_value) {
|
||||
if (UNEXPECTED(!p->key)) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else if (p->key->val[0]) {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
} else {
|
||||
const char *class_name, *prop_name;
|
||||
size_t prop_name_len;
|
||||
zend_unmangle_property_name_ex(
|
||||
p->key, &class_name, &prop_name, &prop_name_len);
|
||||
ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
|
||||
}
|
||||
}
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
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;
|
||||
}
|
||||
}
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = fe_ht->nInternalPointer = pos;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
/* !iter happens from exception */
|
||||
if (iter && ++iter->index > 0) {
|
||||
/* This could cause an endless loop if index becomes zero again.
|
||||
* In case that ever happens we need an additional flag. */
|
||||
iter->funcs->move_forward(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
/* If index is zero we come from FE_RESET and checked valid() already. */
|
||||
if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
|
||||
/* reached end of iteration */
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
value = iter->funcs->get_current_data(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
if (!value) {
|
||||
/* failure in get_current_data */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
if (opline->extended_value) {
|
||||
if (iter->funcs->get_current_key) {
|
||||
iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} else {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -99,8 +99,8 @@ const char *zend_vm_opcodes_map[170] = {
|
||||
"ZEND_UNSET_VAR",
|
||||
"ZEND_UNSET_DIM",
|
||||
"ZEND_UNSET_OBJ",
|
||||
"ZEND_FE_RESET",
|
||||
"ZEND_FE_FETCH",
|
||||
"ZEND_FE_RESET_R",
|
||||
"ZEND_FE_FETCH_R",
|
||||
"ZEND_EXIT",
|
||||
"ZEND_FETCH_R",
|
||||
"ZEND_FETCH_DIM_R",
|
||||
@ -147,8 +147,8 @@ const char *zend_vm_opcodes_map[170] = {
|
||||
"ZEND_DEFINED",
|
||||
"ZEND_TYPE_CHECK",
|
||||
"ZEND_VERIFY_RETURN_TYPE",
|
||||
NULL,
|
||||
NULL,
|
||||
"ZEND_FE_RESET_RW",
|
||||
"ZEND_FE_FETCH_RW",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
@ -101,8 +101,8 @@ END_EXTERN_C()
|
||||
#define ZEND_UNSET_VAR 74
|
||||
#define ZEND_UNSET_DIM 75
|
||||
#define ZEND_UNSET_OBJ 76
|
||||
#define ZEND_FE_RESET 77
|
||||
#define ZEND_FE_FETCH 78
|
||||
#define ZEND_FE_RESET_R 77
|
||||
#define ZEND_FE_FETCH_R 78
|
||||
#define ZEND_EXIT 79
|
||||
#define ZEND_FETCH_R 80
|
||||
#define ZEND_FETCH_DIM_R 81
|
||||
@ -149,6 +149,8 @@ END_EXTERN_C()
|
||||
#define ZEND_DEFINED 122
|
||||
#define ZEND_TYPE_CHECK 123
|
||||
#define ZEND_VERIFY_RETURN_TYPE 124
|
||||
#define ZEND_FE_RESET_RW 125
|
||||
#define ZEND_FE_FETCH_RW 126
|
||||
#define ZEND_PRE_INC_OBJ 132
|
||||
#define ZEND_PRE_DEC_OBJ 133
|
||||
#define ZEND_POST_INC_OBJ 134
|
||||
|
@ -166,14 +166,16 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_NEW:
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
START_BLOCK_OP(ZEND_OP2(opline).opline_num);
|
||||
START_BLOCK_OP(opno + 1);
|
||||
break;
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
START_BLOCK_OP(ZEND_OP2(opline).opline_num);
|
||||
START_BLOCK_OP(opno + 2);
|
||||
break;
|
||||
@ -293,11 +295,13 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_NEW:
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
|
||||
/* break missing intentionally */
|
||||
default:
|
||||
@ -619,7 +623,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
|
||||
ZEND_OP1_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
|
||||
opline->opcode != ZEND_CASE && /* CASE _always_ expects variable */
|
||||
opline->opcode != ZEND_FETCH_LIST &&
|
||||
opline->opcode != ZEND_FE_RESET &&
|
||||
(opline->opcode != ZEND_FE_RESET_R || opline->opcode != ZEND_FE_RESET_RW) &&
|
||||
opline->opcode != ZEND_FREE
|
||||
) {
|
||||
zend_op *src = VAR_SOURCE(opline->op1);
|
||||
|
@ -93,8 +93,10 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_NEW:
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
|
@ -66,15 +66,12 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
|
||||
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
|
||||
start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline;
|
||||
}
|
||||
/* special puprose variable to keep HashPointer on VM stack */
|
||||
/* special puprose variable to keep HashTable* on VM stack */
|
||||
if (opline->opcode == ZEND_OP_DATA &&
|
||||
(opline-1)->opcode == ZEND_FE_FETCH &&
|
||||
(opline-1)->opcode == ZEND_FE_FETCH_RW &&
|
||||
(opline-2)->opcode == ZEND_FE_RESET_RW &&
|
||||
opline->op1_type == IS_TMP_VAR) {
|
||||
start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline;
|
||||
if (sizeof(HashPointer) > sizeof(zval)) {
|
||||
/* Make shure 1 zval is enough for HashPointer (2 must be enough) */
|
||||
start_of_T[VAR_NUM(ZEND_OP1(opline).var) + 1 - offset] = opline;
|
||||
}
|
||||
start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline - 2;
|
||||
}
|
||||
opline--;
|
||||
}
|
||||
@ -88,17 +85,6 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
|
||||
while (opline >= end) {
|
||||
if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) {
|
||||
|
||||
/* special puprose variable to keep HashPointer on VM stack */
|
||||
if (opline->opcode == ZEND_OP_DATA &&
|
||||
(opline-1)->opcode == ZEND_FE_FETCH &&
|
||||
opline->op1_type == IS_TMP_VAR) {
|
||||
max++;
|
||||
ZEND_OP1(opline).var = NUM_VAR(max + offset);
|
||||
if (sizeof(HashPointer) > sizeof(zval)) {
|
||||
/* Make shure 1 zval is enough for HashPointer (2 must be enough) */
|
||||
max++;
|
||||
}
|
||||
} else {
|
||||
currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
|
||||
if (!valid_T[currT]) {
|
||||
GET_AVAILABLE_T();
|
||||
@ -107,7 +93,6 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
|
||||
}
|
||||
ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip OP_DATA */
|
||||
if (opline->opcode == ZEND_OP_DATA &&
|
||||
|
@ -602,8 +602,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
case ZEND_NEW:
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
|
@ -328,7 +328,8 @@ continue_jmp_ex_optimization:
|
||||
op->opcode == ZEND_RETURN ||
|
||||
op->opcode == ZEND_RETURN_BY_REF ||
|
||||
op->opcode == ZEND_FAST_RET ||
|
||||
op->opcode == ZEND_FE_FETCH ||
|
||||
op->opcode == ZEND_FE_FETCH_R ||
|
||||
op->opcode == ZEND_FE_FETCH_RW ||
|
||||
op->opcode == ZEND_EXIT) {
|
||||
break;
|
||||
}
|
||||
@ -363,7 +364,8 @@ continue_jmp_ex_optimization:
|
||||
op->opcode == ZEND_RETURN ||
|
||||
op->opcode == ZEND_RETURN_BY_REF ||
|
||||
op->opcode == ZEND_FAST_RET ||
|
||||
op->opcode == ZEND_FE_FETCH ||
|
||||
op->opcode == ZEND_FE_FETCH_R ||
|
||||
op->opcode == ZEND_FE_FETCH_RW ||
|
||||
op->opcode == ZEND_EXIT) {
|
||||
break;
|
||||
}
|
||||
|
@ -450,8 +450,10 @@ static void zend_accel_optimize(zend_op_array *op_array,
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_NEW:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
|
||||
break;
|
||||
}
|
||||
@ -488,8 +490,10 @@ static void zend_accel_optimize(zend_op_array *op_array,
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_NEW:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
|
||||
break;
|
||||
}
|
||||
|
@ -378,8 +378,10 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_NEW:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
|
||||
break;
|
||||
}
|
||||
|
@ -9,4 +9,4 @@ Bug #23624 (foreach leaves current array key as null)
|
||||
?>
|
||||
--EXPECT--
|
||||
string(3) "one"
|
||||
bool(false)
|
||||
string(3) "one"
|
||||
|
@ -60,5 +60,5 @@ string(1) "f"
|
||||
int(2)
|
||||
string(1) "f"
|
||||
|
||||
bool(false)
|
||||
string(1) "a"
|
||||
bool(false)
|
||||
|
@ -55,6 +55,7 @@ foreach ($refedArray as $k=>&$v4) {
|
||||
Remove elements from a referenced array during loop
|
||||
key: 0; value: original.0
|
||||
key: 1; value: original.1
|
||||
key: 2; value: original.2
|
||||
|
||||
Remove elements from a referenced array during loop, using &$value
|
||||
key: 0; value: original.0
|
||||
@ -64,11 +65,6 @@ Add elements to a referenced array during loop
|
||||
key: 0; value: original.0
|
||||
key: 1; value: original.1
|
||||
key: 2; value: original.2
|
||||
key: 3; value: new.0
|
||||
key: 4; value: new.1
|
||||
key: 5; value: new.2
|
||||
key: 6; value: new.3
|
||||
Loop detected, as expected.
|
||||
|
||||
Add elements to a referenced array during loop, using &$value
|
||||
key: 0; value: original.0
|
||||
|
@ -25,10 +25,9 @@ foreach ($a as $v) {
|
||||
|
||||
Change from array to non iterable:
|
||||
int(1)
|
||||
|
||||
Warning: Invalid argument supplied for foreach() in %s on line 5
|
||||
int(2)
|
||||
int(3)
|
||||
|
||||
Change from object to non iterable:
|
||||
int(1)
|
||||
|
||||
Warning: Invalid argument supplied for foreach() in %s on line 15
|
||||
int(2)
|
||||
|
@ -1,7 +1,5 @@
|
||||
--TEST--
|
||||
Directly modifying a REFERENCED array when foreach'ing over it.
|
||||
--XFAIL--
|
||||
Needs major foreach changes to get sane behavior
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@ -96,7 +94,7 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@ -114,10 +112,9 @@ array(3) {
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
--> State of array after loop:
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
array(0) {
|
||||
}
|
||||
|
||||
---( Array with 4 element(s): )---
|
||||
@ -135,8 +132,8 @@ array(4) {
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=0; $v=v.0
|
||||
iteration 3: $k=0; $v=v.0
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=v.3
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@ -166,7 +163,7 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.1
|
||||
iteration 1: $k=1; $v=v.1
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@ -183,8 +180,8 @@ array(3) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.1
|
||||
iteration 2: $k=0; $v=v.2
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@ -203,9 +200,9 @@ array(4) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.1
|
||||
iteration 2: $k=0; $v=v.2
|
||||
iteration 3: $k=0; $v=v.3
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=v.3
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@ -309,13 +306,8 @@ array(2) {
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=new.0
|
||||
iteration 3: $k=3; $v=new.1
|
||||
iteration 4: $k=4; $v=new.2
|
||||
iteration 5: $k=5; $v=new.3
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(8) {
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
@ -324,14 +316,6 @@ array(8) {
|
||||
string(5) "new.0"
|
||||
[3]=>
|
||||
string(5) "new.1"
|
||||
[4]=>
|
||||
string(5) "new.2"
|
||||
[5]=>
|
||||
string(5) "new.3"
|
||||
[6]=>
|
||||
string(5) "new.4"
|
||||
[7]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
---( Array with 3 element(s): )---
|
||||
@ -348,12 +332,8 @@ array(3) {
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=new.0
|
||||
iteration 4: $k=4; $v=new.1
|
||||
iteration 5: $k=5; $v=new.2
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(9) {
|
||||
array(6) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
@ -366,12 +346,6 @@ array(9) {
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
string(5) "new.2"
|
||||
[6]=>
|
||||
string(5) "new.3"
|
||||
[7]=>
|
||||
string(5) "new.4"
|
||||
[8]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
---( Array with 4 element(s): )---
|
||||
@ -391,11 +365,8 @@ array(4) {
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=v.3
|
||||
iteration 4: $k=4; $v=new.0
|
||||
iteration 5: $k=5; $v=new.1
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(10) {
|
||||
array(8) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
@ -412,10 +383,6 @@ array(10) {
|
||||
string(5) "new.2"
|
||||
[7]=>
|
||||
string(5) "new.3"
|
||||
[8]=>
|
||||
string(5) "new.4"
|
||||
[9]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
|
||||
@ -447,29 +414,16 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=1; $v=v.1
|
||||
--> State of array after loop:
|
||||
array(8) {
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[2]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[3]=>
|
||||
string(3) "v.1"
|
||||
}
|
||||
|
||||
@ -485,31 +439,21 @@ array(3) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
--> State of array after loop:
|
||||
array(9) {
|
||||
array(6) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
[1]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[2]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[3]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[4]=>
|
||||
string(3) "v.1"
|
||||
[8]=>
|
||||
[5]=>
|
||||
string(3) "v.2"
|
||||
}
|
||||
|
||||
@ -527,32 +471,25 @@ array(4) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=v.3
|
||||
--> State of array after loop:
|
||||
array(10) {
|
||||
array(8) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
[1]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
[2]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[3]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[4]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[5]=>
|
||||
string(3) "v.1"
|
||||
[8]=>
|
||||
[6]=>
|
||||
string(3) "v.2"
|
||||
[9]=>
|
||||
[7]=>
|
||||
string(3) "v.3"
|
||||
}
|
||||
|
@ -70,16 +70,12 @@ var_dump($obj);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
|
||||
Substituting the iterated object for a different object.
|
||||
string(10) "Original a"
|
||||
string(10) "Original b"
|
||||
string(5) "new a"
|
||||
string(5) "new b"
|
||||
string(5) "new c"
|
||||
string(5) "new d"
|
||||
string(5) "new e"
|
||||
string(5) "new f"
|
||||
string(10) "Original c"
|
||||
string(10) "Original d"
|
||||
string(10) "Original e"
|
||||
object(stdClass)#%d (6) {
|
||||
["a"]=>
|
||||
string(5) "new a"
|
||||
@ -98,14 +94,9 @@ object(stdClass)#%d (6) {
|
||||
Substituting the iterated object for an array.
|
||||
string(10) "Original a"
|
||||
string(10) "Original b"
|
||||
int(1)
|
||||
int(2)
|
||||
int(3)
|
||||
int(4)
|
||||
int(5)
|
||||
int(6)
|
||||
int(7)
|
||||
int(8)
|
||||
string(10) "Original c"
|
||||
string(10) "Original d"
|
||||
string(10) "Original e"
|
||||
array(8) {
|
||||
[0]=>
|
||||
int(1)
|
||||
@ -128,11 +119,12 @@ array(8) {
|
||||
Substituting the iterated array for an object.
|
||||
int(1)
|
||||
int(2)
|
||||
string(10) "Original a"
|
||||
string(10) "Original b"
|
||||
string(10) "Original c"
|
||||
string(10) "Original d"
|
||||
string(10) "Original e"
|
||||
int(3)
|
||||
int(4)
|
||||
int(5)
|
||||
int(6)
|
||||
int(7)
|
||||
int(8)
|
||||
object(C)#%d (5) {
|
||||
["a"]=>
|
||||
string(10) "Original a"
|
||||
|
Loading…
Reference in New Issue
Block a user