diff --git a/Zend/tests/generators/generator_with_nonscalar_keys.phpt b/Zend/tests/generators/generator_with_nonscalar_keys.phpt new file mode 100644 index 0000000000000..5ae55a1be09a5 --- /dev/null +++ b/Zend/tests/generators/generator_with_nonscalar_keys.phpt @@ -0,0 +1,52 @@ +--TEST-- +Generators can return non-scalar keys +--FILE-- + [4, 5, 6]; + yield (object) ['a' => 'b'] => (object) ['b' => 'a']; + yield 3.14 => 2.73; + yield false => true; + yield true => false; + yield null => null; +} + +foreach (gen() as $k => $v) { + var_dump($k, $v); +} + +?> +--EXPECT-- +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(3) { + [0]=> + int(4) + [1]=> + int(5) + [2]=> + int(6) +} +object(stdClass)#3 (1) { + ["a"]=> + string(1) "b" +} +object(stdClass)#4 (1) { + ["b"]=> + string(1) "a" +} +float(3.14) +float(2.73) +bool(false) +bool(true) +bool(true) +bool(false) +NULL +NULL diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 95c90ea753c8d..2653d0849afa5 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1502,6 +1502,40 @@ ZEND_API int add_get_index_stringl(zval *arg, ulong index, const char *str, uint } /* }}} */ +ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ +{ + int result; + + switch (Z_TYPE_P(key)) { + case IS_STRING: + result = zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL); + break; + case IS_NULL: + result = zend_symtable_update(ht, "", 1, &value, sizeof(zval *), NULL); + break; + case IS_RESOURCE: + zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(key), Z_LVAL_P(key)); + /* break missing intentionally */ + case IS_BOOL: + case IS_LONG: + result = zend_hash_index_update(ht, Z_LVAL_P(key), &value, sizeof(zval *), NULL); + break; + case IS_DOUBLE: + result = zend_hash_index_update(ht, zend_dval_to_lval(Z_LVAL_P(key)), &value, sizeof(zval *), NULL); + break; + default: + zend_error(E_WARNING, "Illegal offset type"); + result = FAILURE; + } + + if (result == SUCCESS) { + Z_ADDREF_P(value); + } + + return result; +} +/* }}} */ + ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long n TSRMLS_DC) /* {{{ */ { zval *tmp; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index fb642c1475587..c26141b1833cf 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -426,6 +426,8 @@ ZEND_API int add_get_index_double(zval *arg, ulong idx, double d, void **dest); ZEND_API int add_get_index_string(zval *arg, ulong idx, const char *str, void **dest, int duplicate); ZEND_API int add_get_index_stringl(zval *arg, ulong idx, const char *str, uint length, void **dest, int duplicate); +ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value); + ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long l TSRMLS_DC); ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC); ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, int b TSRMLS_DC); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 1a8d10890060b..90dceb7fab47c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6360,7 +6360,7 @@ void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token znode key_node; opline = &CG(active_op_array)->opcodes[as_token->u.op.opline_num+1]; - opline->result_type = IS_TMP_VAR; + opline->result_type = IS_VAR; opline->result.opline_num = get_temporary_variable(CG(active_op_array)); GET_NODE(&key_node, opline->result); diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index c1dbee124f386..b90c4f0e5c6af 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -755,31 +755,20 @@ static void zend_generator_iterator_get_data(zend_object_iterator *iterator, zva } /* }}} */ -static int zend_generator_iterator_get_key(zend_object_iterator *iterator, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +static zval *zend_generator_iterator_get_key(zend_object_iterator *iterator TSRMLS_DC) /* {{{ */ { zend_generator *generator = (zend_generator *) iterator->data; zend_generator_ensure_initialized(generator TSRMLS_CC); - if (!generator->key) { - return HASH_KEY_NON_EXISTANT; - } - - if (Z_TYPE_P(generator->key) == IS_LONG) { - *int_key = Z_LVAL_P(generator->key); - return HASH_KEY_IS_LONG; - } - - if (Z_TYPE_P(generator->key) == IS_STRING) { - *str_key = estrndup(Z_STRVAL_P(generator->key), Z_STRLEN_P(generator->key)); - *str_key_len = Z_STRLEN_P(generator->key) + 1; - return HASH_KEY_IS_STRING; + if (generator->key) { + Z_ADDREF_P(generator->key); + return generator->key; + } else { + zval *key; + MAKE_STD_ZVAL(key); + return key; } - - /* Waiting for Etienne's patch to allow arbitrary zval keys. Until then - * error out on non-int and non-string keys. */ - zend_error_noreturn(E_ERROR, "Currently only int and string keys can be yielded"); - return HASH_KEY_NON_EXISTANT; /* Nerver reached */ } /* }}} */ diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 0609d707f533f..7eb9e3eebf973 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1171,6 +1171,27 @@ ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, return HASH_KEY_NON_EXISTANT; } +ZEND_API zval *zend_hash_get_current_key_zval_ex(const HashTable *ht, HashPosition *pos) { + Bucket *p; + zval *key; + + IS_CONSISTENT(ht); + + p = pos ? (*pos) : ht->pInternalPointer; + + ALLOC_INIT_ZVAL(key); + if (!p) { + Z_TYPE_P(key) = IS_NULL; + } else if (p->nKeyLength) { + Z_TYPE_P(key) = IS_STRING; + Z_STRVAL_P(key) = estrndup(p->arKey, p->nKeyLength - 1); + Z_STRLEN_P(key) = p->nKeyLength - 1; + } else { + Z_TYPE_P(key) = IS_LONG; + Z_LVAL_P(key) = p->h; + } + return key; +} ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos) { diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 88c3bfb421ed0..d6f016a5130db 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -177,6 +177,7 @@ ZEND_API ulong zend_hash_next_free_element(const HashTable *ht); ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos); ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos); ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, uint *str_length, ulong *num_index, zend_bool duplicate, HashPosition *pos); +ZEND_API struct _zval_struct *zend_hash_get_current_key_zval_ex(const HashTable *ht, HashPosition *pos); ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos); ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos); ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos); @@ -199,6 +200,8 @@ ZEND_API int zend_hash_set_pointer(HashTable *ht, const HashPointer *ptr); zend_hash_move_backwards_ex(ht, NULL) #define zend_hash_get_current_key(ht, str_index, num_index, duplicate) \ zend_hash_get_current_key_ex(ht, str_index, NULL, num_index, duplicate, NULL) +#define zend_hash_get_current_key_zval(ht) \ + zend_hash_get_current_key_zval_ex(ht, NULL) #define zend_hash_get_current_key_type(ht) \ zend_hash_get_current_key_type_ex(ht, NULL) #define zend_hash_get_current_data(ht, pData) \ diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 384b66da4b545..c51016359040c 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -195,7 +195,7 @@ static int zend_user_it_get_current_key_default(zend_object_iterator *_iter, cha /* }}} */ /* {{{ zend_user_it_get_current_key */ -ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +ZEND_API zval *zend_user_it_get_current_key(zend_object_iterator *_iter TSRMLS_DC) { zend_user_iterator *iter = (zend_user_iterator*)_iter; zval *object = (zval*)iter->it.data; @@ -203,42 +203,14 @@ ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **st zend_call_method_with_0_params(&object, iter->ce, &iter->ce->iterator_funcs.zf_key, "key", &retval); - if (!retval) { - *int_key = 0; - if (!EG(exception)) - { - zend_error(E_WARNING, "Nothing returned from %s::key()", iter->ce->name); - } - return HASH_KEY_IS_LONG; + if (!retval && !EG(exception)) { + zend_error(E_WARNING, "Nothing returned from %s::key()", iter->ce->name); + MAKE_STD_ZVAL(retval); + ZVAL_LONG(retval, 0); } - switch (Z_TYPE_P(retval)) { - default: - zend_error(E_WARNING, "Illegal type returned from %s::key()", iter->ce->name); - case IS_NULL: - *int_key = 0; - zval_ptr_dtor(&retval); - return HASH_KEY_IS_LONG; - - case IS_STRING: - *str_key = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval)); - *str_key_len = Z_STRLEN_P(retval)+1; - zval_ptr_dtor(&retval); - return HASH_KEY_IS_STRING; - case IS_DOUBLE: - *int_key = (long)Z_DVAL_P(retval); - zval_ptr_dtor(&retval); - return HASH_KEY_IS_LONG; - - case IS_RESOURCE: - case IS_BOOL: - case IS_LONG: - *int_key = (long)Z_LVAL_P(retval); - zval_ptr_dtor(&retval); - return HASH_KEY_IS_LONG; - } + return retval; } -/* }}} */ /* {{{ zend_user_it_move_forward */ ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter TSRMLS_DC) diff --git a/Zend/zend_interfaces.h b/Zend/zend_interfaces.h index 23547951ed7dd..e0d92be9e6908 100644 --- a/Zend/zend_interfaces.h +++ b/Zend/zend_interfaces.h @@ -51,7 +51,7 @@ ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend ZEND_API void zend_user_it_rewind(zend_object_iterator *_iter TSRMLS_DC); ZEND_API int zend_user_it_valid(zend_object_iterator *_iter TSRMLS_DC); -ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); +ZEND_API zval *zend_user_it_get_current_key(zend_object_iterator *_iter TSRMLS_DC); ZEND_API void zend_user_it_get_current_data(zend_object_iterator *_iter, zval ***data TSRMLS_DC); ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter TSRMLS_DC); ZEND_API void zend_user_it_invalidate_current(zend_object_iterator *_iter TSRMLS_DC); diff --git a/Zend/zend_iterators.h b/Zend/zend_iterators.h index b484102b20a18..4365e1282daa3 100644 --- a/Zend/zend_iterators.h +++ b/Zend/zend_iterators.h @@ -38,8 +38,8 @@ typedef struct _zend_object_iterator_funcs { /* fetch the item data for the current element */ void (*get_current_data)(zend_object_iterator *iter, zval ***data TSRMLS_DC); - /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */ - int (*get_current_key)(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); + /* fetch the key for the current element */ + zval *(*get_current_key)(zend_object_iterator *iter TSRMLS_DC); /* step forwards to next element */ void (*move_forward)(zend_object_iterator *iter TSRMLS_DC); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f5279378ae71d..c124cb1180931 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4249,13 +4249,10 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) zend_free_op free_op1; zval *array = EX_T(opline->op1.var).fe.ptr; zval **value; - char *str_key; - uint str_key_len; - ulong int_key; HashTable *fe_ht; zend_object_iterator *iter = NULL; - int key_type = 0; zend_bool use_key = (zend_bool)(opline->extended_value & ZEND_FE_FETCH_WITH_KEY); + zval *key = NULL; SAVE_OPLINE(); @@ -4266,8 +4263,11 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); case ZEND_ITER_PLAIN_OBJECT: { - const char *class_name, *prop_name; zend_object *zobj = zend_objects_get_address(array TSRMLS_CC); + int key_type; + char *str_key; + zend_uint str_key_len; + zend_ulong int_key; fe_ht = Z_OBJPROP_P(array); zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); @@ -4281,13 +4281,30 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) zend_hash_move_forward(fe_ht); } while (key_type == HASH_KEY_NON_EXISTANT || (key_type != HASH_KEY_IS_LONG && - zend_check_property_access(zobj, str_key, str_key_len-1 TSRMLS_CC) != SUCCESS)); - zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); - if (use_key && key_type != HASH_KEY_IS_LONG) { - zend_unmangle_property_name_ex(str_key, str_key_len-1, &class_name, &prop_name, &str_key_len); - str_key = estrndup(prop_name, str_key_len); - str_key_len++; + zend_check_property_access(zobj, str_key, str_key_len - 1 TSRMLS_CC) != SUCCESS)); + + if (use_key) { + const char *class_name, *prop_name; + int prop_name_len; + + ALLOC_INIT_ZVAL(key); + switch (key_type) { + case HASH_KEY_IS_STRING: + zend_unmangle_property_name_ex( + str_key, str_key_len - 1, &class_name, &prop_name, &prop_name_len + ); + ZVAL_STRINGL(key, prop_name, prop_name_len, 1); + break; + case HASH_KEY_IS_LONG: + ZVAL_LONG(key, int_key); + break; + case HASH_KEY_NON_EXISTANT: + ZVAL_NULL(key); + break; + } } + + zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); break; } @@ -4299,7 +4316,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } if (use_key) { - key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL); + key = zend_hash_get_current_key_zval(fe_ht); } zend_hash_move_forward(fe_ht); zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); @@ -4336,14 +4353,14 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) } if (use_key) { if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + key = iter->funcs->get_current_key(iter TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor(&array); HANDLE_EXCEPTION(); } } else { - key_type = HASH_KEY_IS_LONG; - int_key = iter->index; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iter->index); } } break; @@ -4360,23 +4377,8 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) } if (use_key) { - zval *key = &EX_T((opline+1)->result.var).tmp_var; - - switch (key_type) { - case HASH_KEY_IS_STRING: - Z_STRVAL_P(key) = (char*)str_key; - Z_STRLEN_P(key) = str_key_len-1; - Z_TYPE_P(key) = IS_STRING; - break; - case HASH_KEY_IS_LONG: - Z_LVAL_P(key) = int_key; - Z_TYPE_P(key) = IS_LONG; - break; - default: - case HASH_KEY_NON_EXISTANT: - ZVAL_NULL(key); - break; - } + /*PZVAL_LOCK(key);*/ + AI_SET_PTR(&EX_T((opline+1)->result.var), key); } CHECK_EXCEPTION(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 10a7a6149e05e..592da2bc48730 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -13592,13 +13592,10 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zval *array = EX_T(opline->op1.var).fe.ptr; zval **value; - char *str_key; - uint str_key_len; - ulong int_key; HashTable *fe_ht; zend_object_iterator *iter = NULL; - int key_type = 0; zend_bool use_key = (zend_bool)(opline->extended_value & ZEND_FE_FETCH_WITH_KEY); + zval *key = NULL; SAVE_OPLINE(); @@ -13609,8 +13606,11 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); case ZEND_ITER_PLAIN_OBJECT: { - const char *class_name, *prop_name; zend_object *zobj = zend_objects_get_address(array TSRMLS_CC); + int key_type; + char *str_key; + zend_uint str_key_len; + zend_ulong int_key; fe_ht = Z_OBJPROP_P(array); zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); @@ -13624,13 +13624,30 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_move_forward(fe_ht); } while (key_type == HASH_KEY_NON_EXISTANT || (key_type != HASH_KEY_IS_LONG && - zend_check_property_access(zobj, str_key, str_key_len-1 TSRMLS_CC) != SUCCESS)); - zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); - if (use_key && key_type != HASH_KEY_IS_LONG) { - zend_unmangle_property_name_ex(str_key, str_key_len-1, &class_name, &prop_name, &str_key_len); - str_key = estrndup(prop_name, str_key_len); - str_key_len++; + zend_check_property_access(zobj, str_key, str_key_len - 1 TSRMLS_CC) != SUCCESS)); + + if (use_key) { + const char *class_name, *prop_name; + int prop_name_len; + + ALLOC_INIT_ZVAL(key); + switch (key_type) { + case HASH_KEY_IS_STRING: + zend_unmangle_property_name_ex( + str_key, str_key_len - 1, &class_name, &prop_name, &prop_name_len + ); + ZVAL_STRINGL(key, prop_name, prop_name_len, 1); + break; + case HASH_KEY_IS_LONG: + ZVAL_LONG(key, int_key); + break; + case HASH_KEY_NON_EXISTANT: + ZVAL_NULL(key); + break; + } } + + zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); break; } @@ -13642,7 +13659,7 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } if (use_key) { - key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL); + key = zend_hash_get_current_key_zval(fe_ht); } zend_hash_move_forward(fe_ht); zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); @@ -13679,14 +13696,15 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } if (use_key) { if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + key = iter->funcs->get_current_key(iter TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor(&array); HANDLE_EXCEPTION(); } - } else { - key_type = HASH_KEY_IS_LONG; - int_key = iter->index; + } + if (!key) { + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iter->index); } } break; @@ -13703,23 +13721,8 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } if (use_key) { - zval *key = &EX_T((opline+1)->result.var).tmp_var; - - switch (key_type) { - case HASH_KEY_IS_STRING: - Z_STRVAL_P(key) = (char*)str_key; - Z_STRLEN_P(key) = str_key_len-1; - Z_TYPE_P(key) = IS_STRING; - break; - case HASH_KEY_IS_LONG: - Z_LVAL_P(key) = int_key; - Z_TYPE_P(key) = IS_LONG; - break; - default: - case HASH_KEY_NON_EXISTANT: - ZVAL_NULL(key); - break; - } + /*PZVAL_LOCK(key);*/ + AI_SET_PTR(&EX_T((opline+1)->result.var), key); } CHECK_EXCEPTION(); diff --git a/ext/com_dotnet/com_iterator.c b/ext/com_dotnet/com_iterator.c index ce4bdd67c04e2..e0cc3d2cc3902 100644 --- a/ext/com_dotnet/com_iterator.c +++ b/ext/com_dotnet/com_iterator.c @@ -74,16 +74,18 @@ static void com_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC *data = &I->zdata; } -static int com_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, - ulong *int_key TSRMLS_DC) +static zval *com_iter_get_key(zend_object_iterator *iter TSRMLS_DC) { struct php_com_iterator *I = (struct php_com_iterator*)iter->data; + zval *key; + MAKE_STD_ZVAL(key); if (I->key == (ulong)-1) { - return HASH_KEY_NON_EXISTANT; + ZVAL_NULL(key); + } else { + ZVAL_LONG(key, I->key); } - *int_key = I->key; - return HASH_KEY_IS_LONG; + return key; } static int com_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC) diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c index ad928497439b5..48d2f76604852 100644 --- a/ext/com_dotnet/com_saproxy.c +++ b/ext/com_dotnet/com_saproxy.c @@ -519,16 +519,18 @@ static void saproxy_iter_get_data(zend_object_iterator *iter, zval ***data TSRML *data = ptr_ptr; } -static int saproxy_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, - ulong *int_key TSRMLS_DC) +static zval *saproxy_iter_get_key(zend_object_iterator *iter TSRMLS_DC) { php_com_saproxy_iter *I = (php_com_saproxy_iter*)iter->data; + zval *key; + MAKE_STD_ZVAL(key); if (I->key == -1) { - return HASH_KEY_NON_EXISTANT; + ZVAL_NULL(key); + } else { + ZVAL_LONG(key, I->key); } - *int_key = (ulong)I->key; - return HASH_KEY_IS_LONG; + return key; } static int saproxy_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index f4115dc7e1d21..4617f5ff6cb12 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -1864,11 +1864,13 @@ static void date_period_it_current_data(zend_object_iterator *iter, zval ***data /* {{{ date_period_it_current_key */ -static int date_period_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +static zval *date_period_it_current_key(zend_object_iterator *iter TSRMLS_DC) { - date_period_it *iterator = (date_period_it *)iter; - *int_key = iterator->current_index; - return HASH_KEY_IS_LONG; + date_period_it *iterator = (date_period_it *)iter; + zval *key; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iterator->current_index); + return key; } /* }}} */ diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index f4183d2f9a4a2..99a753fef7b80 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -157,21 +157,21 @@ static void php_dom_iterator_current_data(zend_object_iterator *iter, zval ***da } /* }}} */ -static int php_dom_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +static zval *php_dom_iterator_current_key(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { zval *curobj; xmlNodePtr curnode = NULL; dom_object *intern; - zval *object; - int namelen; + zval *object, *key; php_dom_iterator *iterator = (php_dom_iterator *)iter; object = (zval *)iterator->intern.data; + MAKE_STD_ZVAL(key); if (instanceof_function(Z_OBJCE_P(object), dom_nodelist_class_entry TSRMLS_CC)) { - *int_key = iter->index; - return HASH_KEY_IS_LONG; + ZVAL_LONG(key, iter->index); + return key; } else { curobj = iterator->curobj; @@ -179,13 +179,11 @@ static int php_dom_iterator_current_key(zend_object_iterator *iter, char **str_k if (intern != NULL && intern->ptr != NULL) { curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; } else { - return HASH_KEY_NON_EXISTANT; + return NULL; } - namelen = xmlStrlen(curnode->name); - *str_key = estrndup(curnode->name, namelen); - *str_key_len = namelen + 1; - return HASH_KEY_IS_STRING; + ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name), 1); + return key; } } /* }}} */ diff --git a/ext/intl/breakiterator/breakiterator_iterators.cpp b/ext/intl/breakiterator/breakiterator_iterators.cpp index d88ad8a712d5b..2ab29a1ae0cea 100644 --- a/ext/intl/breakiterator/breakiterator_iterators.cpp +++ b/ext/intl/breakiterator/breakiterator_iterators.cpp @@ -139,14 +139,13 @@ static void _breakiterator_parts_destroy_it(zend_object_iterator *iter TSRMLS_DC zval_ptr_dtor(reinterpret_cast(&iter->data)); } -static int _breakiterator_parts_get_current_key(zend_object_iterator *iter, - char **str_key, - uint *str_key_len, - ulong *int_key TSRMLS_DC) +static zval *_breakiterator_parts_get_current_key(zend_object_iterator *iter TSRMLS_DC) { /* the actual work is done in move_forward and rewind */ - *int_key = iter->index; - return HASH_KEY_IS_LONG; + zval *key; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iter->index); + return key; } static void _breakiterator_parts_move_forward(zend_object_iterator *iter TSRMLS_DC) @@ -343,4 +342,4 @@ U_CFUNC void breakiterator_register_IntlPartsIterator_class(TSRMLS_D) PARTSITER_DECL_LONG_CONST(KEY_RIGHT); #undef PARTSITER_DECL_LONG_CONST -} \ No newline at end of file +} diff --git a/ext/intl/common/common_enum.cpp b/ext/intl/common/common_enum.cpp index da47a437a67b3..5167718f1d382 100644 --- a/ext/intl/common/common_enum.cpp +++ b/ext/intl/common/common_enum.cpp @@ -251,19 +251,8 @@ static PHP_METHOD(IntlIterator, key) INTLITERATOR_METHOD_FETCH_OBJECT; if (ii->iterator->funcs->get_current_key) { - char *str_key; - uint str_key_len; - ulong int_key; - - switch (ii->iterator->funcs->get_current_key( - ii->iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) { - case HASH_KEY_IS_LONG: - RETURN_LONG(int_key); - break; - case HASH_KEY_IS_STRING: - RETURN_STRINGL(str_key, str_key_len-1, 0); - break; - } + zval *key = ii->iterator->funcs->get_current_key(ii->iterator TSRMLS_CC); + RETURN_ZVAL(key, 1, 1); } else { RETURN_LONG(ii->iterator->index); } diff --git a/ext/intl/resourcebundle/resourcebundle_iterator.c b/ext/intl/resourcebundle/resourcebundle_iterator.c index 16e1b928791ad..29e8c3b4b9c3b 100644 --- a/ext/intl/resourcebundle/resourcebundle_iterator.c +++ b/ext/intl/resourcebundle/resourcebundle_iterator.c @@ -101,22 +101,23 @@ static void resourcebundle_iterator_current( zend_object_iterator *iter, zval ** /* }}} */ /* {{{ resourcebundle_iterator_key */ -static int resourcebundle_iterator_key( zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC ) +static zval *resourcebundle_iterator_key( zend_object_iterator *iter TSRMLS_DC ) { ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter; + zval *key; if (!iterator->current) { resourcebundle_iterator_read( iterator TSRMLS_CC); } + + MAKE_STD_ZVAL(key); if (iterator->is_table) { - *str_key = estrdup( iterator->currentkey ); - *str_key_len = strlen( iterator->currentkey ) + 1; - return HASH_KEY_IS_STRING; - } - else { - *int_key = iterator->i; - return HASH_KEY_IS_LONG; + ZVAL_STRING(key, iterator->currentkey, 1); + } else { + ZVAL_LONG(key, iterator->i); } + + return key; } /* }}} */ diff --git a/ext/mysqli/mysqli_result_iterator.c b/ext/mysqli/mysqli_result_iterator.c index 0f5ccdd63dd7a..659ec56277353 100644 --- a/ext/mysqli/mysqli_result_iterator.c +++ b/ext/mysqli/mysqli_result_iterator.c @@ -150,12 +150,14 @@ static void php_mysqli_result_iterator_rewind(zend_object_iterator *iter TSRMLS_ /* {{{ php_mysqli_result_iterator_current_key */ -static int php_mysqli_result_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +static zval *php_mysqli_result_iterator_current_key(zend_object_iterator *iter TSRMLS_DC) { php_mysqli_result_iterator *iterator = (php_mysqli_result_iterator*) iter; + zval *key; - *int_key = (ulong) iterator->row_num; - return HASH_KEY_IS_LONG; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iterator->row_num); + return key; } /* }}} */ diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 5dc445ff8deb5..0a0d4c3a8938f 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2499,16 +2499,18 @@ static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRM *data = &I->fetch_ahead; } -static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, - ulong *int_key TSRMLS_DC) +static zval *pdo_stmt_iter_get_key(zend_object_iterator *iter TSRMLS_DC) { struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data; + zval *key; + MAKE_STD_ZVAL(key); if (I->key == (ulong)-1) { - return HASH_KEY_NON_EXISTANT; + ZVAL_NULL(key); + } else { + ZVAL_LONG(key, I->key); } - *int_key = I->key; - return HASH_KEY_IS_LONG; + return key; } static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index a6dd2c814603a..1112cfb8b9223 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1434,16 +1434,13 @@ struct _phar_t { static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ { zval **value; - zend_uchar key_type; zend_bool close_fp = 1; - ulong int_key; struct _phar_t *p_obj = (struct _phar_t*) puser; uint str_key_len, base_len = p_obj->l, fname_len; phar_entry_data *data; php_stream *fp; size_t contents_len; char *fname, *error = NULL, *base = p_obj->b, *opened, *save = NULL, *temp = NULL; - phar_zstr key; char *str_key; zend_class_entry *ce = p_obj->c; phar_archive_object *phar_obj = p_obj->p; @@ -1478,35 +1475,23 @@ static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ } if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC); + zval *key = iter->funcs->get_current_key(iter TSRMLS_CC); if (EG(exception)) { return ZEND_HASH_APPLY_STOP; } - if (key_type == HASH_KEY_IS_LONG) { + if (Z_TYPE_P(key) != IS_STRING) { + zval_ptr_dtor(&key); zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name); return ZEND_HASH_APPLY_STOP; } - if (key_type > 9) { /* IS_UNICODE == 10 */ -#if PHP_VERSION_ID < 60000 -/* this can never happen, but fixes a compile warning */ - spprintf(&str_key, 0, "%s", key); -#else - spprintf(&str_key, 0, "%v", key); - ezfree(key); -#endif - } else { - PHAR_STR(key, str_key); - } + str_key_len = Z_STRLEN_P(key); + str_key = estrndup(Z_STRVAL_P(key), str_key_len); save = str_key; - - if (str_key[str_key_len - 1] == '\0') { - str_key_len--; - } - + zval_ptr_dtor(&key); } else { zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name); return ZEND_HASH_APPLY_STOP; @@ -1641,32 +1626,23 @@ static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ } } else { if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &key, &str_key_len, &int_key TSRMLS_CC); + zval *key = iter->funcs->get_current_key(iter TSRMLS_CC); if (EG(exception)) { return ZEND_HASH_APPLY_STOP; } - if (key_type == HASH_KEY_IS_LONG) { + if (Z_TYPE_P(key) != IS_STRING) { + zval_ptr_dtor(&key); zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name); return ZEND_HASH_APPLY_STOP; } - if (key_type > 9) { /* IS_UNICODE == 10 */ -#if PHP_VERSION_ID < 60000 -/* this can never happen, but fixes a compile warning */ - spprintf(&str_key, 0, "%s", key); -#else - spprintf(&str_key, 0, "%v", key); - ezfree(key); -#endif - } else { - PHAR_STR(key, str_key); - } + str_key_len = Z_STRLEN_P(key); + str_key = estrndup(Z_STRVAL_P(key), str_key_len); save = str_key; - - if (str_key[str_key_len - 1] == '\0') str_key_len--; + zval_ptr_dtor(&key); } else { zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Iterator %v returned an invalid key (must return a string)", ce->name); return ZEND_HASH_APPLY_STOP; diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 692516840b2d7..32c74c56b5ae8 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -59,7 +59,7 @@ static zval *sxe_get_value(zval *z TSRMLS_DC); static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC); static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC); static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC); -static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); +static zval *php_sxe_iterator_current_key(zend_object_iterator *iter TSRMLS_DC); static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC); static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC); @@ -2376,12 +2376,11 @@ static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***da } /* }}} */ -static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +static zval *php_sxe_iterator_current_key(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { - zval *curobj; + zval *curobj, *key; xmlNodePtr curnode = NULL; php_sxe_object *intern; - int namelen; php_sxe_iterator *iterator = (php_sxe_iterator *)iter; curobj = iterator->sxe->iter.data; @@ -2391,14 +2390,12 @@ static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_k curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node; } if (!curnode) { - return HASH_KEY_NON_EXISTANT; + return NULL; } - namelen = xmlStrlen(curnode->name); - *str_key = estrndup((char *)curnode->name, namelen); - *str_key_len = namelen + 1; - return HASH_KEY_IS_STRING; - + MAKE_STD_ZVAL(key); + ZVAL_STRINGL(key, (char *) curnode->name, xmlStrlen(curnode->name), 1); + return key; } /* }}} */ diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 897956d91b772..f815eae0dd183 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -2345,19 +2345,22 @@ static xmlNodePtr to_xml_array(encodeTypePtr type, zval *data, int style, xmlNod goto iterator_done; } if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + zval *key = iter->funcs->get_current_key(iter TSRMLS_CC); if (EG(exception)) { goto iterator_done; } - switch(key_type) { - case HASH_KEY_IS_STRING: - add_assoc_zval_ex(array_copy, str_key, str_key_len, *val); - efree(str_key); + switch (Z_TYPE_P(key)) { + case IS_STRING: + add_assoc_zval_ex(array_copy, Z_STRVAL_P(key), Z_STRLEN_P(key)+1, *val); break; - case HASH_KEY_IS_LONG: - add_index_zval(array_copy, int_key, *val); + case IS_LONG: + add_index_zval(array_copy, Z_LVAL_P(key), *val); + break; + default: + /* TODO */ break; } + zval_ptr_dtor(&key); } else { add_next_index_zval(array_copy, *val); } diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 40efc43915b25..7726cfdc842c7 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1018,20 +1018,20 @@ static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***da } /* }}} */ -static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +static zval *spl_array_it_get_current_key(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { spl_array_it *iterator = (spl_array_it *)iter; spl_array_object *object = iterator->object; HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC); if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) { - return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC); + return zend_user_it_get_current_key(iter TSRMLS_CC); } else { if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::current(): " TSRMLS_CC) == FAILURE) { - return HASH_KEY_NON_EXISTANT; + return NULL; } - return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos); + return zend_hash_get_current_key_zval_ex(aht, &object->pos); } } /* }}} */ diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index f43a3709e1308..5f22d0f76e9c8 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1621,7 +1621,7 @@ SPL_METHOD(GlobIterator, count) static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC); static int spl_filesystem_dir_it_valid(zend_object_iterator *iter TSRMLS_DC); static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC); -static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); +static zval *spl_filesystem_dir_it_current_key(zend_object_iterator *iter TSRMLS_DC); static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC); static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC); @@ -1698,12 +1698,13 @@ static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval /* }}} */ /* {{{ spl_filesystem_dir_it_current_key */ -static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +static zval *spl_filesystem_dir_it_current_key(zend_object_iterator *iter TSRMLS_DC) { spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter); - - *int_key = object->u.dir.index; - return HASH_KEY_IS_LONG; + zval *key; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, object->u.dir.index); + return key; } /* }}} */ @@ -1777,19 +1778,18 @@ static void spl_filesystem_tree_it_current_data(zend_object_iterator *iter, zval /* }}} */ /* {{{ spl_filesystem_tree_it_current_key */ -static int spl_filesystem_tree_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +static zval *spl_filesystem_tree_it_current_key(zend_object_iterator *iter TSRMLS_DC) { spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter); - + zval *key; + MAKE_STD_ZVAL(key); if (SPL_FILE_DIR_KEY(object, SPL_FILE_DIR_KEY_AS_FILENAME)) { - *str_key_len = strlen(object->u.dir.entry.d_name) + 1; - *str_key = estrndup(object->u.dir.entry.d_name, *str_key_len - 1); + ZVAL_STRING(key, object->u.dir.entry.d_name, 1); } else { spl_filesystem_object_get_file_name(object TSRMLS_CC); - *str_key_len = object->file_name_len + 1; - *str_key = estrndup(object->file_name, object->file_name_len); + ZVAL_STRINGL(key, object->file_name, object->file_name_len, 1); } - return HASH_KEY_IS_STRING; + return key; } /* }}} */ diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index a8417feada370..6e90fe1b4a77f 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -1023,12 +1023,13 @@ static void spl_dllist_it_get_current_data(zend_object_iterator *iter, zval ***d } /* }}} */ -static int spl_dllist_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +static zval *spl_dllist_it_get_current_key(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { spl_dllist_it *iterator = (spl_dllist_it *)iter; - - *int_key = (ulong) iterator->traverse_position; - return HASH_KEY_IS_LONG; + zval *key; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iterator->traverse_position); + return key; } /* }}} */ diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index c9aec753c80a2..d45cc75ce522c 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -943,18 +943,19 @@ static void spl_fixedarray_it_get_current_data(zend_object_iterator *iter, zval } /* }}} */ -static int spl_fixedarray_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +static zval *spl_fixedarray_it_get_current_key(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter; spl_fixedarray_object *intern = iterator->object; if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_KEY) { - return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC); + return zend_user_it_get_current_key(iter TSRMLS_CC); } else { - *int_key = (ulong) iterator->object->current; - return HASH_KEY_IS_LONG; + zval *key; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iterator->object->current); + return key; } - } /* }}} */ diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index d2de85b2a78c3..85ec011729846 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -949,12 +949,13 @@ static void spl_pqueue_it_get_current_data(zend_object_iterator *iter, zval ***d } /* }}} */ -static int spl_heap_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +static zval *spl_heap_it_get_current_key(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ { spl_heap_it *iterator = (spl_heap_it *)iter; - - *int_key = (ulong) iterator->object->heap->count - 1; - return HASH_KEY_IS_LONG; + zval *key; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iterator->object->heap->count - 1); + return key; } /* }}} */ diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 87b3763cfd7f8..70799bcc9d4d5 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -190,16 +190,18 @@ static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval * sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC); } -static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +static zval *spl_recursive_it_get_current_key(zend_object_iterator *iter TSRMLS_DC) { spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data; zend_object_iterator *sub_iter = object->iterators[object->level].iterator; if (sub_iter->funcs->get_current_key) { - return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC); + return sub_iter->funcs->get_current_key(sub_iter TSRMLS_CC); } else { - *int_key = iter->index; - return HASH_KEY_IS_LONG; + zval *key; + MAKE_STD_ZVAL(key); + ZVAL_LONG(key, iter->index); + return key; } } @@ -617,20 +619,8 @@ SPL_METHOD(RecursiveIteratorIterator, key) } if (iterator->funcs->get_current_key) { - char *str_key; - uint str_key_len; - ulong int_key; - - switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) { - case HASH_KEY_IS_LONG: - RETURN_LONG(int_key); - break; - case HASH_KEY_IS_STRING: - RETURN_STRINGL(str_key, str_key_len-1, 0); - break; - default: - RETURN_NULL(); - } + zval *key = iterator->funcs->get_current_key(iterator TSRMLS_CC); + RETURN_ZVAL(key, 1, 1); } else { RETURN_NULL(); } @@ -1162,65 +1152,56 @@ SPL_METHOD(RecursiveTreeIterator, key) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_object_iterator *iterator = object->iterators[object->level].iterator; - zval prefix, key, postfix, key_copy; + zval prefix, postfix, key_copy; + zval *key; char *str, *ptr; size_t str_len; + int use_copy; if (zend_parse_parameters_none() == FAILURE) { return; } if (iterator->funcs->get_current_key) { - char *str_key; - uint str_key_len; - ulong int_key; - - switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) { - case HASH_KEY_IS_LONG: - ZVAL_LONG(&key, int_key); - break; - case HASH_KEY_IS_STRING: - ZVAL_STRINGL(&key, str_key, str_key_len-1, 0); - break; - default: - ZVAL_NULL(&key); - } + key = iterator->funcs->get_current_key(iterator TSRMLS_CC); } else { - ZVAL_NULL(&key); + ALLOC_INIT_ZVAL(key); } if (object->flags & RTIT_BYPASS_KEY) { - zval *key_ptr = &key; - RETVAL_ZVAL(key_ptr, 1, 0); - zval_dtor(&key); - return; + RETURN_ZVAL(key, 1, 1); } - if (Z_TYPE(key) != IS_STRING) { - int use_copy; - zend_make_printable_zval(&key, &key_copy, &use_copy); + if (Z_TYPE_P(key) != IS_STRING) { + zend_make_printable_zval(key, &key_copy, &use_copy); if (use_copy) { - key = key_copy; + zval_ptr_dtor(&key); + key = &key_copy; } } spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC); spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC); - str_len = Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix); + str_len = Z_STRLEN(prefix) + Z_STRLEN_P(key) + Z_STRLEN(postfix); str = (char *) emalloc(str_len + 1U); ptr = str; memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix)); ptr += Z_STRLEN(prefix); - memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key)); - ptr += Z_STRLEN(key); + memcpy(ptr, Z_STRVAL_P(key), Z_STRLEN_P(key)); + ptr += Z_STRLEN_P(key); memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix)); ptr += Z_STRLEN(postfix); *ptr = 0; + if (use_copy) { + zval_dtor(key); + } else { + zval_ptr_dtor(&key); + } + zval_dtor(&prefix); - zval_dtor(&key); zval_dtor(&postfix); RETVAL_STRINGL(str, str_len, 0); @@ -1590,9 +1571,9 @@ static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC) zval_ptr_dtor(&intern->current.data); intern->current.data = NULL; } - if (intern->current.str_key) { - efree(intern->current.str_key); - intern->current.str_key = NULL; + if (intern->current.key) { + zval_ptr_dtor(&intern->current.key); + intern->current.key = NULL; } if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) { if (intern->u.caching.zstr) { @@ -1636,10 +1617,10 @@ static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more T Z_ADDREF_P(intern->current.data); } if (intern->inner.iterator->funcs->get_current_key) { - intern->current.key_type = intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.str_key, &intern->current.str_key_len, &intern->current.int_key TSRMLS_CC); + intern->current.key = intern->inner.iterator->funcs->get_current_key(intern->inner.iterator TSRMLS_CC); } else { - intern->current.key_type = HASH_KEY_IS_LONG; - intern->current.int_key = intern->current.pos; + MAKE_STD_ZVAL(intern->current.key); + ZVAL_LONG(intern->current.key, intern->current.pos); } return EG(exception) ? FAILURE : SUCCESS; } @@ -1711,12 +1692,8 @@ SPL_METHOD(dual_it, key) SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); - if (intern->current.data) { - if (intern->current.key_type == HASH_KEY_IS_STRING) { - RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1); - } else { - RETURN_LONG(intern->current.int_key); - } + if (intern->current.key) { + RETURN_ZVAL(intern->current.key, 1, 0); } RETURN_NULL(); } /* }}} */ @@ -1927,27 +1904,18 @@ SPL_METHOD(CallbackFilterIterator, accept) zend_fcall_info *fci = &intern->u.cbfilter->fci; zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc; zval **params[3]; - zval zkey; - zval *zkey_p = &zkey; zval *result; if (zend_parse_parameters_none() == FAILURE) { return; } - if (intern->current.data == NULL) { + if (intern->current.data == NULL || intern->current.key == NULL) { RETURN_FALSE; } - - INIT_PZVAL(&zkey); - if (intern->current.key_type == HASH_KEY_IS_LONG) { - ZVAL_LONG(&zkey, intern->current.int_key); - } else { - ZVAL_STRINGL(&zkey, intern->current.str_key, intern->current.str_key_len-1, 0); - } params[0] = &intern->current.data; - params[1] = &zkey_p; + params[1] = &intern->current.key; params[2] = &intern->inner.zobject; fci->retval_ptr_ptr = &result; @@ -1971,9 +1939,9 @@ SPL_METHOD(CallbackFilterIterator, accept) SPL_METHOD(RegexIterator, accept) { spl_dual_it_object *intern; - char *subject, tmp[32], *result; + char *subject, *result; int subject_len, use_copy, count = 0, result_len; - zval subject_copy, zcount, *replacement, tmp_replacement; + zval *subject_ptr, subject_copy, zcount, *replacement, tmp_replacement; if (zend_parse_parameters_none() == FAILURE) { return; @@ -1986,24 +1954,18 @@ SPL_METHOD(RegexIterator, accept) } if (intern->u.regex.flags & REGIT_USE_KEY) { - if (intern->current.key_type == HASH_KEY_IS_LONG) { - subject_len = slprintf(tmp, sizeof(tmp), "%ld", intern->current.int_key); - subject = &tmp[0]; - use_copy = 0; - } else { - subject_len = intern->current.str_key_len - 1; - subject = estrndup(intern->current.str_key, subject_len); - use_copy = 1; - } + subject_ptr = intern->current.key; } else { - zend_make_printable_zval(intern->current.data, &subject_copy, &use_copy); - if (use_copy) { - subject = Z_STRVAL(subject_copy); - subject_len = Z_STRLEN(subject_copy); - } else { - subject = Z_STRVAL_P(intern->current.data); - subject_len = Z_STRLEN_P(intern->current.data); - } + subject_ptr = intern->current.data; + } + + zend_make_printable_zval(subject_ptr, &subject_copy, &use_copy); + if (use_copy) { + subject = Z_STRVAL(subject_copy); + subject_len = Z_STRLEN(subject_copy); + } else { + subject = Z_STRVAL_P(subject_ptr); + subject_len = Z_STRLEN_P(subject_ptr); } switch (intern->u.regex.mode) @@ -2051,12 +2013,9 @@ SPL_METHOD(RegexIterator, accept) result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count TSRMLS_CC); if (intern->u.regex.flags & REGIT_USE_KEY) { - if (intern->current.key_type != HASH_KEY_IS_LONG) { - efree(intern->current.str_key); - } - intern->current.key_type = HASH_KEY_IS_STRING; - intern->current.str_key = result; - intern->current.str_key_len = result_len + 1; + zval_ptr_dtor(&intern->current.key); + MAKE_STD_ZVAL(intern->current.key); + ZVAL_STRINGL(intern->current.key, result, result_len, 0); } else { zval_ptr_dtor(&intern->current.data); MAKE_STD_ZVAL(intern->current.data); @@ -2590,14 +2549,14 @@ static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC) /* Full cache ? */ if (intern->u.caching.flags & CIT_FULL_CACHE) { zval *zcacheval; + zval *key = intern->current.key; MAKE_STD_ZVAL(zcacheval); ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0); - if (intern->current.key_type == HASH_KEY_IS_LONG) { - add_index_zval(intern->u.caching.zcache, intern->current.int_key, zcacheval); - } else { - zend_symtable_update(HASH_OF(intern->u.caching.zcache), intern->current.str_key, intern->current.str_key_len, &zcacheval, sizeof(void*), NULL); - } + + array_set_zval_key(HASH_OF(intern->u.caching.zcache), key, zcacheval); + + zval_ptr_dtor(&zcacheval); } /* Recursion ? */ if (intern->dit_type == DIT_RecursiveCachingIterator) { @@ -2755,13 +2714,9 @@ SPL_METHOD(CachingIterator, __toString) return; } if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) { - if (intern->current.key_type == HASH_KEY_IS_STRING) { - RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1); - } else { - RETVAL_LONG(intern->current.int_key); - convert_to_string(return_value); - return; - } + MAKE_COPY_ZVAL(&intern->current.key, return_value); + convert_to_string(return_value); + return; } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) { MAKE_COPY_ZVAL(&intern->current.data, return_value); convert_to_string(return_value); @@ -3123,19 +3078,8 @@ SPL_METHOD(NoRewindIterator, key) SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); if (intern->inner.iterator->funcs->get_current_key) { - char *str_key; - uint str_key_len; - ulong int_key; - switch (intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) { - case HASH_KEY_IS_LONG: - RETURN_LONG(int_key); - break; - case HASH_KEY_IS_STRING: - RETURN_STRINGL(str_key, str_key_len-1, 0); - break; - default: - RETURN_NULL(); - } + zval *key = intern->inner.iterator->funcs->get_current_key(intern->inner.iterator TSRMLS_CC); + RETURN_ZVAL(key, 1, 1); } else { RETURN_NULL(); } @@ -3502,11 +3446,7 @@ PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, v static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ { - zval **data, *return_value = (zval*)puser; - char *str_key; - uint str_key_len; - ulong int_key; - int key_type; + zval **data, *return_value = (zval*)puser; iter->funcs->get_current_data(iter, &data TSRMLS_CC); if (EG(exception)) { @@ -3516,20 +3456,12 @@ static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser T return ZEND_HASH_APPLY_STOP; } if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + zval *key = iter->funcs->get_current_key(iter TSRMLS_CC); if (EG(exception)) { return ZEND_HASH_APPLY_STOP; } - Z_ADDREF_PP(data); - switch(key_type) { - case HASH_KEY_IS_STRING: - add_assoc_zval_ex(return_value, str_key, str_key_len, *data); - efree(str_key); - break; - case HASH_KEY_IS_LONG: - add_index_zval(return_value, int_key, *data); - break; - } + array_set_zval_key(Z_ARRVAL_P(return_value), key, *data); + zval_ptr_dtor(&key); } else { Z_ADDREF_PP(data); add_next_index_zval(return_value, *data); diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h index 39cc0d1337def..73d9d2e6147f2 100644 --- a/ext/spl/spl_iterators.h +++ b/ext/spl/spl_iterators.h @@ -133,10 +133,7 @@ typedef struct _spl_dual_it_object { } inner; struct { zval *data; - char *str_key; - uint str_key_len; - ulong int_key; - int key_type; /* HASH_KEY_IS_STRING or HASH_KEY_IS_LONG */ + zval *key; int pos; } current; dual_it_type dit_type; diff --git a/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt b/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt new file mode 100644 index 0000000000000..a4cbcc3298f1e --- /dev/null +++ b/ext/spl/tests/iterator_to_array_nonscalar_keys.phpt @@ -0,0 +1,31 @@ +--TEST-- +Tests iterator_to_array() with non-scalar keys +--FILE-- + 0; + yield 1 => 1; + yield 2.5 => 2; + yield null => 3; + yield [] => 4; + yield new stdClass => 5; +} + +var_dump(iterator_to_array(gen())); + +?> +--EXPECTF-- +Warning: Illegal offset type in %s on line %d + +Warning: Illegal offset type in %s on line %d +array(4) { + ["foo"]=> + int(0) + [1]=> + int(1) + [0]=> + int(2) + [""]=> + int(3) +} diff --git a/ext/spl/tests/multiple_iterator_001.phpt b/ext/spl/tests/multiple_iterator_001.phpt index edd03f5040883..eb77f79371ba8 100644 --- a/ext/spl/tests/multiple_iterator_001.phpt +++ b/ext/spl/tests/multiple_iterator_001.phpt @@ -23,8 +23,8 @@ echo "-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_K var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC)); -foreach($m as $value) { - var_dump($m->key(), $value); +foreach($m as $key => $value) { + var_dump($key, $value); } try { $m->current(); @@ -42,8 +42,8 @@ echo "-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUM $m->setFlags(MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC); var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC)); -foreach($m as $value) { - var_dump($m->key(), $value); +foreach($m as $key => $value) { + var_dump($key, $value); } echo "-- Default flags, added element --\n"; @@ -51,8 +51,8 @@ echo "-- Default flags, added element --\n"; $m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC); $iter2[] = 3; -foreach($m as $value) { - var_dump($m->key(), $value); +foreach($m as $key => $value) { + var_dump($key, $value); } echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL --\n"; @@ -71,8 +71,8 @@ $m->attachIterator($iter1, "iter1"); $m->attachIterator($iter2, b"iter2"); $m->attachIterator($iter3, 3); -foreach($m as $value) { - var_dump($m->key(), $value); +foreach($m as $key => $value) { + var_dump($key, $value); } echo "-- Associate with invalid value --\n"; @@ -98,8 +98,8 @@ var_dump($m->containsIterator($iter2)); var_dump($m->detachIterator($iter2)); var_dump($m->countIterators()); var_dump($m->containsIterator($iter2)); -foreach($m as $value) { - var_dump($m->key(), $value); +foreach($m as $key => $value) { + var_dump($key, $value); } ?>