summaryrefslogtreecommitdiff
path: root/ext/standard/array.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/standard/array.c')
-rw-r--r--ext/standard/array.c301
1 files changed, 170 insertions, 131 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c
index eb4cd6b417..7b6fca0647 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2018 The PHP Group |
+ | Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -28,11 +28,7 @@
#include <math.h>
#include <time.h>
#include <stdio.h>
-#if HAVE_STRING_H
#include <string.h>
-#else
-#include <strings.h>
-#endif
#ifdef PHP_WIN32
#include "win32/unistd.h"
#endif
@@ -174,7 +170,7 @@ static int php_array_key_compare(const void *a, const void *b) /* {{{ */
}
}
}
- return l1 > l2 ? 1 : (l1 < l2 ? -1 : 0);
+ return ZEND_NORMALIZE_BOOL(l1 - l2);
}
/* }}} */
@@ -982,7 +978,7 @@ static int php_array_user_compare(const void *a, const void *b) /* {{{ */
zval_ptr_dtor(&retval);
zval_ptr_dtor(&args[1]);
zval_ptr_dtor(&args[0]);
- return ret < 0 ? -1 : ret > 0 ? 1 : 0;
+ return ZEND_NORMALIZE_BOOL(ret);
} else {
zval_ptr_dtor(&args[1]);
zval_ptr_dtor(&args[0]);
@@ -1105,7 +1101,7 @@ static int php_array_user_key_compare(const void *a, const void *b) /* {{{ */
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&args[1]);
- return result < 0 ? -1 : result > 0 ? 1 : 0;
+ return ZEND_NORMALIZE_BOOL(result);
}
/* }}} */
@@ -1790,9 +1786,11 @@ static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table
zend_throw_error(NULL, "Cannot re-assign $this");
return -1;
}
- ZVAL_DEREF(orig_var);
- zval_ptr_dtor(orig_var);
- ZVAL_COPY_DEREF(orig_var, entry);
+ ZVAL_DEREF(entry);
+ ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
+ if (UNEXPECTED(EG(exception))) {
+ return -1;
+ }
count++;
}
} ZEND_HASH_FOREACH_END();
@@ -1873,9 +1871,11 @@ static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table
if (zend_string_equals_literal(var_name, "GLOBALS")) {
continue;
}
- ZVAL_DEREF(orig_var);
- zval_ptr_dtor(orig_var);
- ZVAL_COPY_DEREF(orig_var, entry);
+ ZVAL_DEREF(entry);
+ ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
+ if (UNEXPECTED(EG(exception))) {
+ return -1;
+ }
} else {
ZVAL_DEREF(entry);
Z_TRY_ADDREF_P(entry);
@@ -1975,9 +1975,11 @@ static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbo
if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
orig_var = Z_INDIRECT_P(orig_var);
}
- ZVAL_DEREF(orig_var);
- zval_ptr_dtor(orig_var);
- ZVAL_COPY(orig_var, entry);
+ ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
+ if (UNEXPECTED(EG(exception))) {
+ zend_string_release_ex(Z_STR(final_name), 0);
+ return -1;
+ }
} else {
Z_TRY_ADDREF_P(entry);
zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
@@ -2101,9 +2103,11 @@ static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_tab
if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
orig_var = Z_INDIRECT_P(orig_var);
}
- ZVAL_DEREF(orig_var);
- zval_ptr_dtor(orig_var);
- ZVAL_COPY(orig_var, entry);
+ ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
+ if (UNEXPECTED(EG(exception))) {
+ zend_string_release_ex(Z_STR(final_name), 0);
+ return -1;
+ }
} else {
Z_TRY_ADDREF_P(entry);
zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
@@ -2206,9 +2210,11 @@ static zend_long php_extract_prefix_all(zend_array *arr, zend_array *symbol_tabl
if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
orig_var = Z_INDIRECT_P(orig_var);
}
- ZVAL_DEREF(orig_var);
- zval_ptr_dtor(orig_var);
- ZVAL_COPY(orig_var, entry);
+ ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
+ if (UNEXPECTED(EG(exception))) {
+ zend_string_release_ex(Z_STR(final_name), 0);
+ return -1;
+ }
} else {
Z_TRY_ADDREF_P(entry);
zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
@@ -2313,9 +2319,11 @@ static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_
if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
orig_var = Z_INDIRECT_P(orig_var);
}
- ZVAL_DEREF(orig_var);
- zval_ptr_dtor(orig_var);
- ZVAL_COPY(orig_var, entry);
+ ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0);
+ if (UNEXPECTED(EG(exception))) {
+ zend_string_release_ex(Z_STR(final_name), 0);
+ return -1;
+ }
} else {
Z_TRY_ADDREF_P(entry);
zend_hash_add_new(symbol_table, Z_STR(final_name), entry);
@@ -3732,102 +3740,142 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ *
}
/* }}} */
-static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace) /* {{{ */
+static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */
{
zval *args = NULL;
zval *arg;
int argc, i;
+ HashTable *dest;
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_VARIADIC('+', args, argc)
ZEND_PARSE_PARAMETERS_END();
- if (replace) {
- HashTable *dest;
-
- for (i = 0; i < argc; i++) {
- zval *arg = args + i;
+ for (i = 0; i < argc; i++) {
+ zval *arg = args + i;
- if (Z_TYPE_P(arg) != IS_ARRAY) {
- php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg));
- RETURN_NULL();
- }
+ if (Z_TYPE_P(arg) != IS_ARRAY) {
+ php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg));
+ RETURN_NULL();
}
+ }
- /* copy first array */
- arg = args;
- dest = zend_array_dup(Z_ARRVAL_P(arg));
- ZVAL_ARR(return_value, dest);
- if (recursive) {
- for (i = 1; i < argc; i++) {
- arg = args + i;
- php_array_replace_recursive(dest, Z_ARRVAL_P(arg));
- }
- } else {
- for (i = 1; i < argc; i++) {
- arg = args + i;
- zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1);
- }
+ /* copy first array */
+ arg = args;
+ dest = zend_array_dup(Z_ARRVAL_P(arg));
+ ZVAL_ARR(return_value, dest);
+ if (recursive) {
+ for (i = 1; i < argc; i++) {
+ arg = args + i;
+ php_array_replace_recursive(dest, Z_ARRVAL_P(arg));
}
} else {
- zval *src_entry;
- HashTable *src, *dest;
- uint32_t count = 0;
+ for (i = 1; i < argc; i++) {
+ arg = args + i;
+ zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1);
+ }
+ }
+}
+/* }}} */
- for (i = 0; i < argc; i++) {
- zval *arg = args + i;
+static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */
+{
+ zval *args = NULL;
+ zval *arg;
+ int argc, i;
+ zval *src_entry;
+ HashTable *src, *dest;
+ uint32_t count = 0;
- if (Z_TYPE_P(arg) != IS_ARRAY) {
- php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg));
- RETURN_NULL();
- }
- count += zend_hash_num_elements(Z_ARRVAL_P(arg));
- }
-
- arg = args;
- src = Z_ARRVAL_P(arg);
- /* copy first array */
- array_init_size(return_value, count);
- dest = Z_ARRVAL_P(return_value);
- if (HT_FLAGS(src) & HASH_FLAG_PACKED) {
- zend_hash_real_init_packed(dest);
- ZEND_HASH_FILL_PACKED(dest) {
- ZEND_HASH_FOREACH_VAL(src, src_entry) {
- if (UNEXPECTED(Z_ISREF_P(src_entry) &&
- Z_REFCOUNT_P(src_entry) == 1)) {
- src_entry = Z_REFVAL_P(src_entry);
+ ZEND_PARSE_PARAMETERS_START(1, -1)
+ Z_PARAM_VARIADIC('+', args, argc)
+ ZEND_PARSE_PARAMETERS_END();
+
+ for (i = 0; i < argc; i++) {
+ zval *arg = args + i;
+
+ if (Z_TYPE_P(arg) != IS_ARRAY) {
+ php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg));
+ RETURN_NULL();
+ }
+ count += zend_hash_num_elements(Z_ARRVAL_P(arg));
+ }
+
+ if (argc == 2) {
+ zval *ret = NULL;
+
+ if (zend_hash_num_elements(Z_ARRVAL(args[0])) == 0) {
+ ret = &args[1];
+ } else if (zend_hash_num_elements(Z_ARRVAL(args[1])) == 0) {
+ ret = &args[0];
+ }
+ if (ret) {
+ if (HT_FLAGS(Z_ARRVAL_P(ret)) & HASH_FLAG_PACKED) {
+ if (HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(ret))) {
+ ZVAL_COPY(return_value, ret);
+ return;
+ }
+ } else {
+ zend_bool copy = 1;
+ zend_string *string_key;
+
+ ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(ret), string_key) {
+ if (!string_key) {
+ copy = 0;
+ break;
}
- Z_TRY_ADDREF_P(src_entry);
- ZEND_HASH_FILL_ADD(src_entry);
} ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FILL_END();
- } else {
- zend_string *string_key;
- zend_hash_real_init_mixed(dest);
- ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
+ if (copy) {
+ ZVAL_COPY(return_value, ret);
+ return;
+ }
+ }
+ }
+ }
+
+ arg = args;
+ src = Z_ARRVAL_P(arg);
+ /* copy first array */
+ array_init_size(return_value, count);
+ dest = Z_ARRVAL_P(return_value);
+ if (HT_FLAGS(src) & HASH_FLAG_PACKED) {
+ zend_hash_real_init_packed(dest);
+ ZEND_HASH_FILL_PACKED(dest) {
+ ZEND_HASH_FOREACH_VAL(src, src_entry) {
if (UNEXPECTED(Z_ISREF_P(src_entry) &&
Z_REFCOUNT_P(src_entry) == 1)) {
src_entry = Z_REFVAL_P(src_entry);
}
Z_TRY_ADDREF_P(src_entry);
- if (EXPECTED(string_key)) {
- _zend_hash_append(dest, string_key, src_entry);
- } else {
- zend_hash_next_index_insert_new(dest, src_entry);
- }
+ ZEND_HASH_FILL_ADD(src_entry);
} ZEND_HASH_FOREACH_END();
- }
- if (recursive) {
- for (i = 1; i < argc; i++) {
- arg = args + i;
- php_array_merge_recursive(dest, Z_ARRVAL_P(arg));
+ } ZEND_HASH_FILL_END();
+ } else {
+ zend_string *string_key;
+ zend_hash_real_init_mixed(dest);
+ ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) {
+ if (UNEXPECTED(Z_ISREF_P(src_entry) &&
+ Z_REFCOUNT_P(src_entry) == 1)) {
+ src_entry = Z_REFVAL_P(src_entry);
}
- } else {
- for (i = 1; i < argc; i++) {
- arg = args + i;
- php_array_merge(dest, Z_ARRVAL_P(arg));
+ Z_TRY_ADDREF_P(src_entry);
+ if (EXPECTED(string_key)) {
+ _zend_hash_append(dest, string_key, src_entry);
+ } else {
+ zend_hash_next_index_insert_new(dest, src_entry);
}
+ } ZEND_HASH_FOREACH_END();
+ }
+ if (recursive) {
+ for (i = 1; i < argc; i++) {
+ arg = args + i;
+ php_array_merge_recursive(dest, Z_ARRVAL_P(arg));
+ }
+ } else {
+ for (i = 1; i < argc; i++) {
+ arg = args + i;
+ php_array_merge(dest, Z_ARRVAL_P(arg));
}
}
}
@@ -3837,7 +3885,7 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE
Merges elements from passed arrays into one array */
PHP_FUNCTION(array_merge)
{
- php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
+ php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
@@ -3845,7 +3893,7 @@ PHP_FUNCTION(array_merge)
Recursively merges elements from passed arrays into one array */
PHP_FUNCTION(array_merge_recursive)
{
- php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
+ php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
@@ -3853,7 +3901,7 @@ PHP_FUNCTION(array_merge_recursive)
Replaces elements from passed arrays into one array */
PHP_FUNCTION(array_replace)
{
- php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
+ php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
@@ -3861,7 +3909,7 @@ PHP_FUNCTION(array_replace)
Recursively replaces elements from passed arrays into one array */
PHP_FUNCTION(array_replace_recursive)
{
- php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1);
+ php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
@@ -4099,10 +4147,6 @@ static inline zval *array_column_fetch_prop(zval *data, zval *name, zval *rv) /*
zval *prop = NULL;
if (Z_TYPE_P(data) == IS_OBJECT) {
- if (!Z_OBJ_HANDLER_P(data, has_property) || !Z_OBJ_HANDLER_P(data, read_property)) {
- return NULL;
- }
-
/* The has_property check is first performed in "exists" mode (which returns true for
* properties that are null but exist) and then in "has" mode to handle objects that
* implement __isset (which is not called in "exists" mode). */
@@ -4589,7 +4633,7 @@ static int zval_user_compare(zval *a, zval *b) /* {{{ */
if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
zend_long ret = zval_get_long(&retval);
zval_ptr_dtor(&retval);
- return ret < 0 ? -1 : ret > 0 ? 1 : 0;
+ return ZEND_NORMALIZE_BOOL(ret);
} else {
return 0;
}
@@ -6137,7 +6181,7 @@ PHP_FUNCTION(array_map)
ZVAL_COPY(&arg, zv);
ret = zend_call_function(&fci, &fci_cache);
- i_zval_ptr_dtor(&arg ZEND_FILE_LINE_CC);
+ i_zval_ptr_dtor(&arg);
if (ret != SUCCESS || Z_TYPE(result) == IS_UNDEF) {
zend_array_destroy(Z_ARR_P(return_value));
RETURN_NULL();
@@ -6250,34 +6294,38 @@ PHP_FUNCTION(array_map)
Checks if the given key or index exists in the array */
PHP_FUNCTION(array_key_exists)
{
- zval *key; /* key to check for */
- HashTable *array; /* array to check in */
+ zval *key;
+ zval *array;
+ HashTable *ht;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_ZVAL(key)
- Z_PARAM_ARRAY_OR_OBJECT_HT(array)
+ Z_PARAM_ARRAY_OR_OBJECT(array)
ZEND_PARSE_PARAMETERS_END();
+ if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
+ ht = Z_ARRVAL_P(array);
+ } else {
+ ht = zend_get_properties_for(array, ZEND_PROP_PURPOSE_ARRAY_CAST);
+ }
+
switch (Z_TYPE_P(key)) {
case IS_STRING:
- if (zend_symtable_exists_ind(array, Z_STR_P(key))) {
- RETURN_TRUE;
- }
- RETURN_FALSE;
+ RETVAL_BOOL(zend_symtable_exists_ind(ht, Z_STR_P(key)));
+ break;
case IS_LONG:
- if (zend_hash_index_exists(array, Z_LVAL_P(key))) {
- RETURN_TRUE;
- }
- RETURN_FALSE;
+ RETVAL_BOOL(zend_hash_index_exists(ht, Z_LVAL_P(key)));
+ break;
case IS_NULL:
- if (zend_hash_exists_ind(array, ZSTR_EMPTY_ALLOC())) {
- RETURN_TRUE;
- }
- RETURN_FALSE;
-
+ RETVAL_BOOL(zend_hash_exists_ind(ht, ZSTR_EMPTY_ALLOC()));
+ break;
default:
php_error_docref(NULL, E_WARNING, "The first argument should be either a string or an integer");
- RETURN_FALSE;
+ RETVAL_FALSE;
+ }
+
+ if (Z_TYPE_P(array) != IS_ARRAY) {
+ zend_release_properties(ht);
}
}
/* }}} */
@@ -6404,12 +6452,3 @@ PHP_FUNCTION(array_combine)
} ZEND_HASH_FOREACH_END();
}
/* }}} */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: noet sw=4 ts=4 fdm=marker
- * vim<600: noet sw=4 ts=4
- */