diff --git a/ext/standard/array.c b/ext/standard/array.c index 79c9ab6207ad..0fff8b344388 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -5531,6 +5531,125 @@ PHP_FUNCTION(array_combine) } /* }}} */ +/* {{{ php_array_key_index_common + offset_type: 0: determine from parameters; 1 = first; -1 = last + */ +static void php_array_key_index_common(INTERNAL_FUNCTION_PARAMETERS, int offset_type) +{ + int argc; + zval *input, *outValue; + int key_offset; + int writeValue; + zval *arrValue; + HashPosition pos; + int key_type; + zend_string *string_key; + zend_ulong num_key; + zend_bool direction; + + argc = ZEND_NUM_ARGS(); + + if(offset_type == 0) { + key_offset = 0; + + //array_key_index(array input, int offset, [mixed value]) + if(zend_parse_parameters(argc TSRMLS_CC, "al|z/", &input, &key_offset, &outValue) == FAILURE) { + RETURN_NULL(); + } + + writeValue = (argc >= 3); + } else { + if(offset_type == 1) { + key_offset = 0; + } else { + key_offset = offset_type; + } + + //array_key_(first|last)(array input, [mixed value]) + if(zend_parse_parameters(argc TSRMLS_CC, "a|z/", &input, &outValue) == FAILURE) { + RETURN_NULL(); + } + + writeValue = (argc >= 2); + } + + //true == forward; false == backwards + direction = (key_offset >= 0); + if(!direction) { + key_offset = abs(key_offset) - 1; + } + + if(key_offset >= zend_hash_num_elements(Z_ARRVAL_P(input))) { + RETURN_NULL(); + } + + if(direction) { + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos); + } else { + zend_hash_internal_pointer_end_ex(Z_ARRVAL_P(input), &pos); + } + + if(key_offset >= 1) { + while(key_offset--) { + if(direction) { + zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos); + } else { + zend_hash_move_backwards_ex(Z_ARRVAL_P(input), &pos); + } + } + } + + key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &num_key, &pos); + + switch(key_type) { + case HASH_KEY_IS_LONG: + RETVAL_LONG(num_key); + break; + + case HASH_KEY_IS_STRING: + RETVAL_STR_COPY(string_key); + break; + + case HASH_KEY_NON_EXISTENT: + default: + RETURN_NULL(); + break; + } + + if(writeValue) { + zval_dtor(outValue); + + arrValue = zend_hash_get_current_data_ex(Z_ARRVAL_P(input), &pos); + + ZVAL_COPY_VALUE(outValue, arrValue); + } +} +/* }}} */ + +/* {{{ proto mixed array_key_index(array input, int index [, mixed value]) + Return the array's index key (and optionally, value) */ +PHP_FUNCTION(array_key_index) +{ + php_array_key_index_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto mixed array_key_first(array input [, mixed value]) + Return the array's first key (and optionally, value) */ +PHP_FUNCTION(array_key_first) +{ + php_array_key_index_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + +/* {{{ proto mixed array_key_last(array input [, mixed value]) + Return the array's last key (and optionally, value) */ +PHP_FUNCTION(array_key_last) +{ + php_array_key_index_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, -1); +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 5334e26439b7..adc7018496c3 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -601,6 +601,19 @@ ZEND_BEGIN_ARG_INFO(arginfo_array_combine, 0) ZEND_ARG_INFO(0, keys) /* ARRAY_INFO(0, keys, 0) */ ZEND_ARG_INFO(0, values) /* ARRAY_INFO(0, values, 0) */ ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_key_index, 0) + ZEND_ARG_INFO(0, input) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(1, value) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_key_first, 0) + ZEND_ARG_INFO(0, input) + ZEND_ARG_INFO(1, value) +ZEND_END_ARG_INFO() /* }}} */ /* {{{ basic_functions.c */ ZEND_BEGIN_ARG_INFO(arginfo_get_magic_quotes_gpc, 0) @@ -3341,6 +3354,9 @@ const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(array_chunk, arginfo_array_chunk) PHP_FE(array_combine, arginfo_array_combine) PHP_FE(array_key_exists, arginfo_array_key_exists) + PHP_FE(array_key_index, arginfo_array_key_index) + PHP_FE(array_key_first, arginfo_array_key_first) + PHP_FE(array_key_last, arginfo_array_key_first) /* aliases from array.c */ PHP_FALIAS(pos, current, arginfo_current) diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h index ba2490c98b84..e5fbd6cf672e 100644 --- a/ext/standard/php_array.h +++ b/ext/standard/php_array.h @@ -102,6 +102,9 @@ PHP_FUNCTION(array_map); PHP_FUNCTION(array_key_exists); PHP_FUNCTION(array_chunk); PHP_FUNCTION(array_combine); +PHP_FUNCTION(array_key_index); +PHP_FUNCTION(array_key_first); +PHP_FUNCTION(array_key_last); PHPAPI int php_array_merge(HashTable *dest, HashTable *src); PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src); diff --git a/ext/standard/tests/array/array_key_index.phpt b/ext/standard/tests/array/array_key_index.phpt new file mode 100644 index 000000000000..119c50444a03 --- /dev/null +++ b/ext/standard/tests/array/array_key_index.phpt @@ -0,0 +1,222 @@ +--TEST-- +array_key_first, array_key_last, array_key_index +--FILE-- + 'first', + 'two' => 'middle', + 'three' => 'last', +); +array_key_index_test($arr); +array_key_index_test_value($arr); + +echo "test with numeric array\n"; +$arr = array( + 1 => 'first', + 2 => 'middle', + 3 => 'last', +); +array_key_index_test($arr); +array_key_index_test_value($arr); + +echo "test with mixed array\n"; +$arr = array( + 1 => 'first', + 'second' => 'middle', + 3 => 'last', +); +array_key_index_test($arr); +array_key_index_test_value($arr); +?> +--EXPECT-- +test with string array +string(3) "one" +middle + +string(5) "three" +middle + +string(3) "two" +middle + +string(3) "one" +middle + +NULL +middle + + +string(3) "one" +string(5) "first" +middle + +string(5) "three" +string(4) "last" +middle + +string(3) "two" +string(6) "middle" +middle + +string(3) "one" +string(5) "first" +middle + +NULL +string(5) "first" +middle + + +test with numeric array +int(1) +middle + +int(3) +middle + +int(2) +middle + +int(1) +middle + +NULL +middle + + +int(1) +string(5) "first" +middle + +int(3) +string(4) "last" +middle + +int(2) +string(6) "middle" +middle + +int(1) +string(5) "first" +middle + +NULL +string(5) "first" +middle + + +test with mixed array +int(1) +middle + +int(3) +middle + +string(6) "second" +middle + +int(1) +middle + +NULL +middle + + +int(1) +string(5) "first" +middle + +int(3) +string(4) "last" +middle + +string(6) "second" +string(6) "middle" +middle + +int(1) +string(5) "first" +middle + +NULL +string(5) "first" +middle