Skip to content

Add implementation and tests for array_key_first, array_key_last and array_value_first, array_value_last #3256

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 4 commits 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
33 changes: 33 additions & 0 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -4016,6 +4016,39 @@ PHP_FUNCTION(array_keys)
}
/* }}} */

/* {{{ proto mixed array_key_first(array stack)
Get the key of the first element of the array */
PHP_FUNCTION(array_key_first)
{
zval *stack; /* Input stack */

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_EX(stack, 0, 1)
ZEND_PARSE_PARAMETERS_END();

HashTable *target_hash = HASH_OF(stack);
HashPosition pos = 0;
zend_hash_get_current_key_zval_ex(target_hash, return_value, &pos);
}
/* }}} */

/* {{{ proto mixed array_key_last(array stack)
Get the key of the last element of the array */
PHP_FUNCTION(array_key_last)
{
zval *stack; /* Input stack */
HashPosition pos;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_EX(stack, 0, 1)
ZEND_PARSE_PARAMETERS_END();

HashTable *target_hash = HASH_OF(stack);
zend_hash_internal_pointer_end_ex(target_hash, &pos);
zend_hash_get_current_key_zval_ex(target_hash, return_value, &pos);
}
/* }}} */

/* {{{ proto array array_values(array input)
Return just the values from the input array */
PHP_FUNCTION(array_values)
Expand Down
11 changes: 11 additions & 0 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,15 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_array_keys, 0, 0, 1)
ZEND_ARG_INFO(0, strict)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_array_key_first, 0)
ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the comment ARRAY_INFO, instead of just using ZEND_ARG_ARRAY_INFO ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't use the typed arginfo parameters, yet. @nikic recently suggested to stick with that for now to avoid duplicate checks, IIRC.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I adopted it from existing functions for consistency so I guess keep it?

ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_array_key_last, 0)
ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */
ZEND_END_ARG_INFO()


ZEND_BEGIN_ARG_INFO(arginfo_array_values, 0)
ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */
ZEND_END_ARG_INFO()
Expand Down Expand Up @@ -3362,6 +3371,8 @@ static const zend_function_entry basic_functions[] = { /* {{{ */
PHP_FE(array_replace, arginfo_array_replace)
PHP_FE(array_replace_recursive, arginfo_array_replace_recursive)
PHP_FE(array_keys, arginfo_array_keys)
PHP_FE(array_key_first, arginfo_array_key_first)
PHP_FE(array_key_last, arginfo_array_key_last)
PHP_FE(array_values, arginfo_array_values)
PHP_FE(array_count_values, arginfo_array_count_values)
PHP_FE(array_column, arginfo_array_column)
Expand Down
2 changes: 2 additions & 0 deletions ext/standard/php_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ PHP_FUNCTION(array_merge_recursive);
PHP_FUNCTION(array_replace);
PHP_FUNCTION(array_replace_recursive);
PHP_FUNCTION(array_keys);
PHP_FUNCTION(array_key_first);
PHP_FUNCTION(array_key_last);
PHP_FUNCTION(array_values);
PHP_FUNCTION(array_count_values);
PHP_FUNCTION(array_column);
Expand Down
234 changes: 234 additions & 0 deletions ext/standard/tests/array/array_key_first.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
--TEST--
Test array_key_first() function
--FILE--
<?php

array_key_first($GLOBALS);

/* Various combinations of arrays to be used for the test */
$mixed_array = array(
array(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add test cases with:

  • A single element here: array( "foo" );
  • An array where there is one element, and it doesn't start with index 0: array( 1 => "42" ),

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good additional cases, I'll add them to the tests for all four functions.

Thanks for the input!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the cases to the accepted two functions

array( 1,2,3,4,5,6,7,8,9 ),
array( "One", "_Two", "Three", "Four", "Five" ),
array( 6, "six", 7, "seven", 8, "eight", 9, "nine" ),
array( "a" => "aaa", "A" => "AAA", "c" => "ccc", "d" => "ddd", "e" => "eee" ),
array( "1" => "one", "2" => "two", "3" => "three", "4" => "four", "5" => "five" ),
array( 1 => "one", 2 => "two", 3 => 7, 4 => "four", 5 => "five" ),
array( "f" => "fff", "1" => "one", 4 => 6, "" => "blank", 2.4 => "float", "F" => "FFF",
"blank" => "", 3.7 => 3.7, 5.4 => 7, 6 => 8.6, '5' => "Five", "4name" => "jonny", "a" => NULL, NULL => 3 ),
array( 12, "name", 'age', '45' ),
array( array("oNe", "tWo", 4), array(10, 20, 30, 40, 50), array() ),
array( "one" => 1, "one" => 2, "three" => 3, 3, 4, 3 => 33, 4 => 44, 5, 6,
5.4 => 54, 5.7 => 57, "5.4" => 554, "5.7" => 557 ),
array( "foo" ),
array( 1 => "42" )
);

/* Loop to test normal functionality with different arrays inputs */
echo "\n*** Normal testing with various array inputs ***\n";

$counter = 1;
foreach( $mixed_array as $sub_array )
{
echo "\n-- Input Array for Iteration $counter is --\n";
print_r( $sub_array );
echo "\nFirst key is :\n";
var_dump( array_key_first($sub_array) );
$counter++;
}

echo"\nDone";
?>
--EXPECT--
*** Normal testing with various array inputs ***

-- Input Array for Iteration 1 is --
Array
(
)

First key is :
NULL

-- Input Array for Iteration 2 is --
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
[8] => 9
)

First key is :
int(0)

-- Input Array for Iteration 3 is --
Array
(
[0] => One
[1] => _Two
[2] => Three
[3] => Four
[4] => Five
)

First key is :
int(0)

-- Input Array for Iteration 4 is --
Array
(
[0] => 6
[1] => six
[2] => 7
[3] => seven
[4] => 8
[5] => eight
[6] => 9
[7] => nine
)

First key is :
int(0)

-- Input Array for Iteration 5 is --
Array
(
[a] => aaa
[A] => AAA
[c] => ccc
[d] => ddd
[e] => eee
)

First key is :
string(1) "a"

-- Input Array for Iteration 6 is --
Array
(
[1] => one
[2] => two
[3] => three
[4] => four
[5] => five
)

First key is :
int(1)

-- Input Array for Iteration 7 is --
Array
(
[1] => one
[2] => two
[3] => 7
[4] => four
[5] => five
)

First key is :
int(1)

-- Input Array for Iteration 8 is --
Array
(
[f] => fff
[1] => one
[4] => 6
[] => 3
[2] => float
[F] => FFF
[blank] =>
[3] => 3.7
[5] => Five
[6] => 8.6
[4name] => jonny
[a] =>
)

First key is :
string(1) "f"

-- Input Array for Iteration 9 is --
Array
(
[0] => 12
[1] => name
[2] => age
[3] => 45
)

First key is :
int(0)

-- Input Array for Iteration 10 is --
Array
(
[0] => Array
(
[0] => oNe
[1] => tWo
[2] => 4
)

[1] => Array
(
[0] => 10
[1] => 20
[2] => 30
[3] => 40
[4] => 50
)

[2] => Array
(
)

)

First key is :
int(0)

-- Input Array for Iteration 11 is --
Array
(
[one] => 2
[three] => 3
[0] => 3
[1] => 4
[3] => 33
[4] => 44
[5] => 57
[6] => 6
[5.4] => 554
[5.7] => 557
)

First key is :
string(3) "one"

-- Input Array for Iteration 12 is --
Array
(
[0] => foo
)

First key is :
int(0)

-- Input Array for Iteration 13 is --
Array
(
[1] => 42
)

First key is :
int(1)

Done
52 changes: 52 additions & 0 deletions ext/standard/tests/array/array_key_first_errors.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
--TEST--
Test array_key_first() function (errors)
--FILE--
<?php

$empty_array = array();
$number = 5;
$str = "abc";

/* Various combinations of arrays to be used for the test */
$mixed_array = array(
array( 1,2,3,4,5,6,7,8,9 ),
array( "One", "_Two", "Three", "Four", "Five" )
);

/* Testing Error Conditions */
echo "\n*** Testing Error Conditions ***\n";

/* Zero argument */
var_dump( array_key_first() );

/* Scalar argument */
var_dump( array_key_first($number) );

/* String argument */
var_dump( array_key_first($str) );

/* Invalid Number of arguments */
var_dump( array_key_first($mixed_array[0],$mixed_array[1]) );

/* Empty Array as argument */
var_dump( array_key_first($empty_array) );

echo"\nDone";
?>
--EXPECTF--
*** Testing Error Conditions ***

Warning: array_key_first() expects exactly 1 parameter, 0 given in %s on line %d
NULL

Warning: array_key_first() expects parameter 1 to be array, int given in %s on line %d
NULL

Warning: array_key_first() expects parameter 1 to be array, string given in %s on line %d
NULL

Warning: array_key_first() expects exactly 1 parameter, 2 given in %s on line %d
NULL
NULL

Done
36 changes: 36 additions & 0 deletions ext/standard/tests/array/array_key_first_variation.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
Test array_key_first() function (variation)
--FILE--
<?php

/* Various combinations of arrays to be used for the test */
$array = array( 1,2,3,4,5,6,7,8,9 );

echo"\n*** Checking for internal array pointer not being changed by array_key_first ***\n";

echo "\nCurrent Element is : ";
var_dump( current($array) );

echo "\nNext Element is : ";
var_dump( next($array) );

echo "\nFirst key is : ";
var_dump( array_key_first($array) );

echo "\nCurrent Element after array_key_first operation is: ";
var_dump( current($array) );

echo"\nDone";
?>
--EXPECT--
*** Checking for internal array pointer not being changed by array_key_first ***

Current Element is : int(1)

Next Element is : int(2)

First key is : int(0)

Current Element after array_key_first operation is: int(2)

Done
Loading