Skip to content

Add array_key_first(), array_key_last(), and array_key_index() #347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions ext/standard/php_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
222 changes: 222 additions & 0 deletions ext/standard/tests/array/array_key_index.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
--TEST--
array_key_first, array_key_last, array_key_index
--FILE--
<?php

function array_key_index_test($arr)
{
reset($arr);
next($arr); //skip to second parameter

$key = array_key_first($arr);
var_dump($key);
echo current($arr) . "\n";
echo "\n";


$key = array_key_last($arr);
var_dump($key);
echo current($arr) . "\n";
echo "\n";

$key = array_key_index($arr, 1);

var_dump($key);
echo current($arr) . "\n";
echo "\n";

$key = array_key_index($arr, -3);

var_dump($key);
echo current($arr) . "\n";
echo "\n";

$key = array_key_index($arr, 3);
var_dump($key);
echo current($arr) . "\n";

echo "\n\n";
}

function array_key_index_test_value($arr)
{
reset($arr);
next($arr); //skip to second parameter

$value = array('value has not been written to');

$key = array_key_first($arr, $value);
var_dump($key);
var_dump($value);
echo current($arr) . "\n";
echo "\n";


$key = array_key_last($arr, $value);
var_dump($key);
var_dump($value);
echo current($arr) . "\n";
echo "\n";

$key = array_key_index($arr, 1, $value);

var_dump($key);
var_dump($value);
echo current($arr) . "\n";
echo "\n";

$key = array_key_index($arr, -3, $value);

var_dump($key);
var_dump($value);
echo current($arr) . "\n";
echo "\n";

$key = array_key_index($arr, 3, $value);
var_dump($key);
var_dump($value);
echo current($arr) . "\n";

echo "\n\n";
}

echo "test with string array\n";
$arr = array(
'one' => '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