summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/standard/array.c113
-rw-r--r--ext/standard/basic_functions.c1
-rw-r--r--ext/standard/php_array.h1
3 files changed, 114 insertions, 1 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 6b73339446..c3c7ca8d76 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -2941,7 +2941,7 @@ PHP_FUNCTION(array_filter)
} else
zval_ptr_dtor(&retval);
} else {
- php_error(E_WARNING, "%s() had an error invoking the reduction callback", get_active_function_name());
+ php_error(E_WARNING, "%s() had an error invoking the filter callback", get_active_function_name());
return;
}
} else if (!zend_is_true(*operand))
@@ -2964,6 +2964,117 @@ PHP_FUNCTION(array_filter)
/* }}} */
+/* {{{ proto array array_map(mixed callback, array input1 [, array input2 ,...])
+ Applies the callback to the elements in given arrays. */
+PHP_FUNCTION(array_map)
+{
+ zval ***args = NULL;
+ zval ***params;
+ zval *callback;
+ zval *result, *null;
+ char *callback_name;
+ int i, k, maxlen = 0;
+ int *array_len;
+
+ if (ZEND_NUM_ARGS() < 2) {
+ WRONG_PARAM_COUNT;
+ }
+
+ args = (zval ***)emalloc(ZEND_NUM_ARGS() * sizeof(zval **));
+ if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
+ efree(args);
+ WRONG_PARAM_COUNT;
+ }
+
+ callback = *args[0];
+ if (Z_TYPE_P(callback) != IS_NULL && !zend_is_callable(callback, 0, &callback_name)) {
+ php_error(E_WARNING, "%s() expects argument 1, '%s', to be either NULL or a valid callback",
+ get_active_function_name(), callback_name);
+ efree(callback_name);
+ efree(args);
+ return;
+ }
+
+ /* Cache array sizes. */
+ array_len = (int*)emalloc((ZEND_NUM_ARGS()-1) * sizeof(int));
+
+ /* Check that arrays are indeed arrays and calculate maximum size. */
+ for (i = 0; i < ZEND_NUM_ARGS()-1; i++) {
+ if (Z_TYPE_PP(args[i+1]) != IS_ARRAY) {
+ php_error(E_WARNING, "%s() expects argument %d to be an array",
+ get_active_function_name(), i + 2);
+ efree(array_len);
+ efree(args);
+ return;
+ }
+ array_len[i] = zend_hash_num_elements(Z_ARRVAL_PP(args[i+1]));
+ if (array_len[i] > maxlen)
+ maxlen = array_len[i];
+ }
+
+ /* Short-circuit: if no callback and only one array, just return it. */
+ if (Z_TYPE_P(callback) == IS_NULL && ZEND_NUM_ARGS() == 2) {
+ *return_value = **args[1];
+ zval_copy_ctor(return_value);
+ efree(array_len);
+ efree(args);
+ return;
+ }
+
+ array_init(return_value);
+ params = (zval ***)emalloc((ZEND_NUM_ARGS()-1) * sizeof(zval **));
+ MAKE_STD_ZVAL(null);
+ ZVAL_NULL(null);
+
+ /* We iterate through all the arrays at once. */
+ for (k = 0; k < maxlen; k++) {
+ /*
+ * If no callback, the result will be an array, consisting of current
+ * entries from all arrays.
+ */
+ if (Z_TYPE_P(callback) == IS_NULL) {
+ MAKE_STD_ZVAL(result);
+ array_init(result);
+ }
+
+ for (i = 0; i < ZEND_NUM_ARGS()-1; i++) {
+ /*
+ * If this array still hash elements, add the current one to the
+ * parameter list, otherwise use null value.
+ */
+ if (k < array_len[i]) {
+ zend_hash_index_find(Z_ARRVAL_PP(args[i+1]), k, (void **)&params[i]);
+ } else {
+ if (Z_TYPE_P(callback) == IS_NULL)
+ zval_add_ref(&null);
+ params[i] = &null;
+ }
+
+ if (Z_TYPE_P(callback) == IS_NULL)
+ add_next_index_zval(result, *params[i]);
+ }
+
+ if (Z_TYPE_P(callback) != IS_NULL) {
+ if (!call_user_function_ex(EG(function_table), NULL, callback, &result, ZEND_NUM_ARGS()-1, params, 0, NULL) == SUCCESS && result) {
+ php_error(E_WARNING, "%s() had an error invoking the map callback", get_active_function_name());
+ efree(array_len);
+ efree(args);
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+ }
+
+ add_next_index_zval(return_value, result);
+ }
+
+ zval_ptr_dtor(&null);
+ efree(params);
+ efree(array_len);
+ efree(args);
+}
+/* }}} */
+
+
/*
* Local variables:
* tab-width: 4
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index f8a1fca45a..bf2142d7e7 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -582,6 +582,7 @@ function_entry basic_functions[] = {
PHP_FE(array_diff, NULL)
PHP_FE(array_sum, NULL)
PHP_FE(array_filter, NULL)
+ PHP_FE(array_map, NULL)
/* aliases from array.c */
PHP_FALIAS(pos, current, first_arg_force_ref)
diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h
index 226574df92..fb00e2d08a 100644
--- a/ext/standard/php_array.h
+++ b/ext/standard/php_array.h
@@ -76,6 +76,7 @@ PHP_FUNCTION(array_intersect);
PHP_FUNCTION(array_diff);
PHP_FUNCTION(array_sum);
PHP_FUNCTION(array_filter);
+PHP_FUNCTION(array_map);
HashTable* php_splice(HashTable *, int, int, zval ***, int, HashTable **);
PHPAPI void php_array_merge(HashTable *dest, HashTable *src, int recursive);