-
Notifications
You must be signed in to change notification settings - Fork 7.9k
RFC: array_change_keys #1925
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
RFC: array_change_keys #1925
Changes from all commits
6e92f23
6c9e469
5844d9c
47136c2
f368def
eae1ae3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3776,6 +3776,65 @@ PHP_FUNCTION(array_change_key_case) | |
} | ||
/* }}} */ | ||
|
||
/** {{{ proto array array_change_keys(array input, mixed callback) | ||
Retuns an array with all keys modified by a callback */ | ||
PHP_FUNCTION(array_change_keys) | ||
{ | ||
zval *array, *value, *params; | ||
zval result; | ||
zend_fcall_info fci; | ||
zend_fcall_info_cache fci_cache = empty_fcall_info_cache; | ||
zend_ulong num_key; | ||
zend_string *str_key; | ||
|
||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "af", &array, &fci, &fci_cache) == FAILURE) { | ||
return; | ||
} | ||
|
||
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array))); | ||
params = (zval *)safe_emalloc(2, sizeof(zval), 0); | ||
|
||
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, str_key, value) { | ||
fci.retval = &result; | ||
fci.param_count = 2; | ||
fci.params = params; | ||
fci.no_separation = 0; | ||
|
||
if (str_key) { | ||
ZVAL_STR_COPY(¶ms[0], str_key); | ||
} else { | ||
ZVAL_LONG(¶ms[0], num_key); | ||
} | ||
ZVAL_COPY(¶ms[1], value); | ||
|
||
if (zend_call_function(&fci, &fci_cache) != SUCCESS || Z_TYPE(result) == IS_UNDEF) { | ||
zval_dtor(return_value); | ||
zval_dtor(¶ms[0]); | ||
zval_dtor(¶ms[1]); | ||
efree(params); | ||
RETURN_NULL(); | ||
} | ||
|
||
zval_dtor(¶ms[0]); | ||
zval_dtor(¶ms[1]); | ||
|
||
if (Z_TYPE(result) == IS_STRING) { | ||
value = zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR(result), value); | ||
zval_add_ref(value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nervermind. |
||
} else if (Z_TYPE(result) == IS_LONG) { | ||
value = zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL(result), value); | ||
zval_add_ref(value); | ||
} else { | ||
php_error_docref(NULL, E_WARNING, "New key should be either a string or an integer"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you'd better also tell the user which key is illegal. |
||
} | ||
|
||
zval_ptr_dtor(&result); | ||
} ZEND_HASH_FOREACH_END(); | ||
|
||
efree(params); | ||
} | ||
/* }}} */ | ||
|
||
struct bucketindex { | ||
Bucket b; | ||
unsigned int i; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -452,6 +452,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_array_change_key_case, 0, 0, 1) | |
ZEND_ARG_INFO(0, case) | ||
ZEND_END_ARG_INFO() | ||
|
||
ZEND_BEGIN_ARG_INFO_EX(arginfo_array_change_keys, 0, 0, 1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the required num arg should be 2 here |
||
ZEND_ARG_INFO(0, input) /* ARRAY_INFO(0, arg, 0) */ | ||
ZEND_ARG_INFO(0, callback) | ||
ZEND_END_ARG_INFO() | ||
|
||
ZEND_BEGIN_ARG_INFO_EX(arginfo_array_unique, 0, 0, 1) | ||
ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ | ||
ZEND_ARG_INFO(0, flags) | ||
|
@@ -3312,6 +3317,7 @@ const zend_function_entry basic_functions[] = { /* {{{ */ | |
PHP_FE(array_pad, arginfo_array_pad) | ||
PHP_FE(array_flip, arginfo_array_flip) | ||
PHP_FE(array_change_key_case, arginfo_array_change_key_case) | ||
PHP_FE(array_change_keys, arginfo_array_change_keys) | ||
PHP_FE(array_rand, arginfo_array_rand) | ||
PHP_FE(array_unique, arginfo_array_unique) | ||
PHP_FE(array_intersect, arginfo_array_intersect) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
--TEST-- | ||
Test array_change_keys() function | ||
--FILE-- | ||
<?php | ||
$arrayWithIntKeys = ['foo', 'bar']; | ||
$arrayWithStringKeys = ['foo' => 42, 'bar' => 3]; | ||
$arrayWithMixedKeys = ['foo' => 42, 'bar']; | ||
|
||
echo "---Testing an empty array---\n"; | ||
var_dump(array_change_keys([], function(){})); | ||
|
||
echo "---Numeric keys to numeric keys---\n"; | ||
var_dump(array_change_keys($arrayWithIntKeys, function($k, $v) { | ||
return $k * 10; | ||
})); | ||
|
||
echo "---Numeric keys to string keys---\n"; | ||
var_dump(array_change_keys($arrayWithIntKeys, function($k, $v) { | ||
return 'test:' . $k; | ||
})); | ||
|
||
echo "---String keys to numeric keys---\n"; | ||
$i = 0; | ||
var_dump(array_change_keys($arrayWithIntKeys, function($k, $v) use (&$i) { | ||
return $i++; | ||
})); | ||
|
||
echo "---String keys to string keys---\n"; | ||
var_dump(array_change_keys($arrayWithStringKeys, function($k, $v) { | ||
return 'test:' . $k; | ||
})); | ||
|
||
echo "---Mixed keys to numeric keys---\n"; | ||
$i = 10; | ||
var_dump(array_change_keys($arrayWithMixedKeys, function($k, $v) use (&$i) { | ||
return $i++; | ||
})); | ||
|
||
echo "---Mixed keys to string keys---\n"; | ||
var_dump(array_change_keys($arrayWithMixedKeys, function($k, $v) { | ||
return 'test:' . $k; | ||
})); | ||
|
||
echo "---Mixed keys to mixed keys---\n"; | ||
var_dump(array_change_keys($arrayWithMixedKeys, function($k, $v) { | ||
return is_int($k) ? 'baz' : 3; | ||
})); | ||
|
||
echo "---Test using a string as the callable---\n"; | ||
// We can't reference 'md5' directly because it would get a truthy value in its second param, | ||
// This resulting in some raw bytes instead of a nice human-readable string. | ||
function use_md5_hash_as_key($k, $v) { | ||
return md5($k); | ||
} | ||
var_dump(array_change_keys($arrayWithMixedKeys, 'use_md5_hash_as_key')); | ||
|
||
echo "---Test using the [\$obj, 'method'] callback syntax\n"; | ||
$keyMaker = new class { | ||
function getNewKey($k, $v) { | ||
return md5($v); | ||
} | ||
}; | ||
var_dump(array_change_keys($arrayWithMixedKeys, [$keyMaker, 'getNewKey'])); | ||
|
||
?> | ||
--EXPECTF-- | ||
---Testing an empty array--- | ||
array(0) { | ||
} | ||
---Numeric keys to numeric keys--- | ||
array(2) { | ||
[0]=> | ||
string(3) "foo" | ||
[10]=> | ||
string(3) "bar" | ||
} | ||
---Numeric keys to string keys--- | ||
array(2) { | ||
["test:0"]=> | ||
string(3) "foo" | ||
["test:1"]=> | ||
string(3) "bar" | ||
} | ||
---String keys to numeric keys--- | ||
array(2) { | ||
[0]=> | ||
string(3) "foo" | ||
[1]=> | ||
string(3) "bar" | ||
} | ||
---String keys to string keys--- | ||
array(2) { | ||
["test:foo"]=> | ||
int(42) | ||
["test:bar"]=> | ||
int(3) | ||
} | ||
---Mixed keys to numeric keys--- | ||
array(2) { | ||
[10]=> | ||
int(42) | ||
[11]=> | ||
string(3) "bar" | ||
} | ||
---Mixed keys to string keys--- | ||
array(2) { | ||
["test:foo"]=> | ||
int(42) | ||
["test:0"]=> | ||
string(3) "bar" | ||
} | ||
---Mixed keys to mixed keys--- | ||
array(2) { | ||
[3]=> | ||
int(42) | ||
["baz"]=> | ||
string(3) "bar" | ||
} | ||
---Test using a string as the callable--- | ||
array(2) { | ||
["acbd18db4cc2f85cedef654fccc4a4d8"]=> | ||
int(42) | ||
["cfcd208495d565ef66e7dff9f98764da"]=> | ||
string(3) "bar" | ||
} | ||
---Test using the [$obj, 'method'] callback syntax | ||
array(2) { | ||
["a1d0c6e83f027327d8461063f4ac58a6"]=> | ||
int(42) | ||
["37b51d194a7513e45b56f6524f2d51f2"]=> | ||
string(3) "bar" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--TEST-- | ||
Test array_change_keys() function with duplicate keys | ||
--FILE-- | ||
<?php | ||
|
||
var_dump(array_change_keys([1, 2, 3], function(){ return 'foo'; })); | ||
|
||
var_dump(array_change_keys([1, 2, 3], function(){ return 99; })); | ||
|
||
var_dump(array_change_keys(range(1, 10), function($k, $v){ return $k % 2 ? 'foo' : 99; })); | ||
|
||
?> | ||
--EXPECTF-- | ||
array(1) { | ||
["foo"]=> | ||
int(3) | ||
} | ||
array(1) { | ||
[99]=> | ||
int(3) | ||
} | ||
array(2) { | ||
[99]=> | ||
int(9) | ||
["foo"]=> | ||
int(10) | ||
} |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since the size is fixed, you could use stack allocated zval[2]