📄 array.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 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 | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Andi Gutmans <andi@zend.com> | | Zeev Suraski <zeev@zend.com> | | Rasmus Lerdorf <rasmus@php.net> | | Andrei Zmievski <andrei@php.net> | | Stig Venaas <venaas@php.net> | | Jason Greene <jason@php.net> | +----------------------------------------------------------------------+*//* $Id: array.c,v 1.199.2.44.2.16 2007/03/16 20:08:25 stas Exp $ */#include "php.h"#include "php_ini.h"#include <stdarg.h>#include <stdlib.h>#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#include "zend_globals.h"#include "php_globals.h"#include "php_array.h"#include "basic_functions.h"#include "php_string.h"#include "php_rand.h"#include "php_smart_str.h"#ifdef ZTSint array_globals_id;#elsephp_array_globals array_globals;#endif#define EXTR_OVERWRITE 0#define EXTR_SKIP 1#define EXTR_PREFIX_SAME 2#define EXTR_PREFIX_ALL 3#define EXTR_PREFIX_INVALID 4#define EXTR_PREFIX_IF_EXISTS 5#define EXTR_IF_EXISTS 6#define EXTR_REFS 0x100#define SORT_REGULAR 0#define SORT_NUMERIC 1#define SORT_STRING 2#define SORT_LOCALE_STRING 5#define SORT_DESC 3#define SORT_ASC 4#define CASE_LOWER 0#define CASE_UPPER 1#define COUNT_NORMAL 0#define COUNT_RECURSIVE 1#define DIFF_NORMAL 0#define DIFF_ASSOC 1#define INTERSECT_NORMAL 0#define INTERSECT_ASSOC 1PHP_MINIT_FUNCTION(array){#ifdef ZTS ts_allocate_id(&array_globals_id, sizeof(php_array_globals), NULL, NULL);#endif REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SORT_ASC", SORT_ASC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SORT_DESC", SORT_DESC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SORT_REGULAR", SORT_REGULAR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SORT_NUMERIC", SORT_NUMERIC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SORT_STRING", SORT_STRING, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT); return SUCCESS;}PHP_MSHUTDOWN_FUNCTION(array){#ifdef ZTS ts_free_id(array_globals_id);#endif return SUCCESS;}static void set_compare_func(int sort_type TSRMLS_DC){ switch (sort_type) { case SORT_NUMERIC: ARRAYG(compare_func) = numeric_compare_function; break; case SORT_STRING: ARRAYG(compare_func) = string_compare_function; break;#if HAVE_STRCOLL case SORT_LOCALE_STRING: ARRAYG(compare_func) = string_locale_compare_function; break;#endif case SORT_REGULAR: default: ARRAYG(compare_func) = compare_function; break; }}static int array_key_compare(const void *a, const void *b TSRMLS_DC){ Bucket *f; Bucket *s; zval result; zval first; zval second; f = *((Bucket **) a); s = *((Bucket **) b); if (f->nKeyLength == 0) { Z_TYPE(first) = IS_LONG; Z_LVAL(first) = f->h; } else { Z_TYPE(first) = IS_STRING; Z_STRVAL(first) = f->arKey; Z_STRLEN(first) = f->nKeyLength-1; } if (s->nKeyLength == 0) { Z_TYPE(second) = IS_LONG; Z_LVAL(second) = s->h; } else { Z_TYPE(second) = IS_STRING; Z_STRVAL(second) = s->arKey; Z_STRLEN(second) = s->nKeyLength-1; } if (ARRAYG(compare_func)(&result, &first, &second TSRMLS_CC) == FAILURE) { return 0; } if (Z_TYPE(result) == IS_DOUBLE) { if (Z_DVAL(result) < 0) { return -1; } else if (Z_DVAL(result) > 0) { return 1; } else { return 0; } } convert_to_long(&result); if (Z_LVAL(result) < 0) { return -1; } else if (Z_LVAL(result) > 0) { return 1; } return 0;}static int array_reverse_key_compare(const void *a, const void *b TSRMLS_DC){ return array_key_compare(a, b TSRMLS_CC) * -1;}/* {{{ proto bool krsort(array array_arg [, int sort_flags]) Sort an array by key value in reverse order */PHP_FUNCTION(krsort){ zval *array; long sort_type = SORT_REGULAR; HashTable *target_hash; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) { RETURN_FALSE; } target_hash = HASH_OF(array); set_compare_func(sort_type TSRMLS_CC); if (zend_hash_sort(target_hash, zend_qsort, array_reverse_key_compare, 0 TSRMLS_CC) == FAILURE) { RETURN_FALSE; } RETURN_TRUE;}/* }}} *//* {{{ proto bool ksort(array array_arg [, int sort_flags]) Sort an array by key */PHP_FUNCTION(ksort){ zval *array; long sort_type = SORT_REGULAR; HashTable *target_hash; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) { RETURN_FALSE; } target_hash = HASH_OF(array); set_compare_func(sort_type TSRMLS_CC); if (zend_hash_sort(target_hash, zend_qsort, array_key_compare, 0 TSRMLS_CC) == FAILURE) { RETURN_FALSE; } RETURN_TRUE;}/* }}} */static int php_count_recursive(zval *array, long mode TSRMLS_DC){ long cnt = 0; zval **element; if (Z_TYPE_P(array) == IS_ARRAY) { cnt = zend_hash_num_elements(Z_ARRVAL_P(array)); if (mode == COUNT_RECURSIVE) { HashPosition pos; for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &element, &pos) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)) { cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC); } } } return cnt;}/* {{{ proto int count(mixed var [, int mode]) Count the number of elements in a variable (usually an array) */PHP_FUNCTION(count){ zval *array; long mode = COUNT_NORMAL; if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) return; switch (Z_TYPE_P(array)) { case IS_NULL: RETURN_LONG(0); break; case IS_ARRAY: RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC)); break; default: RETURN_LONG(1); break; }}/* }}} *//* Numbers are always smaller than strings int this function as it * anyway doesn't make much sense to compare two different data types. * This keeps it consistant and simple. * * This is not correct any more, depends on what compare_func is set to. */static int array_data_compare(const void *a, const void *b TSRMLS_DC){ Bucket *f; Bucket *s; pval result; pval *first; pval *second; f = *((Bucket **) a); s = *((Bucket **) b); first = *((pval **) f->pData); second = *((pval **) s->pData); if (ARRAYG(compare_func)(&result, first, second TSRMLS_CC) == FAILURE) { return 0; } if (Z_TYPE(result) == IS_DOUBLE) { if (Z_DVAL(result) < 0) { return -1; } else if (Z_DVAL(result) > 0) { return 1; } else { return 0; } } convert_to_long(&result); if (Z_LVAL(result) < 0) { return -1; } else if (Z_LVAL(result) > 0) { return 1; } return 0;}static int array_reverse_data_compare(const void *a, const void *b TSRMLS_DC){ return array_data_compare(a, b TSRMLS_CC)*-1;}static int array_natural_general_compare(const void *a, const void *b, int fold_case){ Bucket *f, *s; zval *fval, *sval; zval first, second; int result; f = *((Bucket **) a); s = *((Bucket **) b); fval = *((pval **) f->pData); sval = *((pval **) s->pData); first = *fval; second = *sval; if (Z_TYPE_P(fval) != IS_STRING) { zval_copy_ctor(&first); convert_to_string(&first); } if (Z_TYPE_P(sval) != IS_STRING) { zval_copy_ctor(&second); convert_to_string(&second); } result = strnatcmp_ex(Z_STRVAL(first), Z_STRLEN(first), Z_STRVAL(second), Z_STRLEN(second), fold_case); if (Z_TYPE_P(fval) != IS_STRING) zval_dtor(&first); if (Z_TYPE_P(sval) != IS_STRING) zval_dtor(&second); return result;}static int array_natural_compare(const void *a, const void *b TSRMLS_DC){ return array_natural_general_compare(a, b, 0);}static int array_natural_case_compare(const void *a, const void *b TSRMLS_DC){ return array_natural_general_compare(a, b, 1);}static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case){ zval **array; HashTable *target_hash; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) { WRONG_PARAM_COUNT; } target_hash = HASH_OF(*array); if (!target_hash) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array"); return; } if (fold_case) { if (zend_hash_sort(target_hash, zend_qsort, array_natural_case_compare, 0 TSRMLS_CC) == FAILURE) { return; } } else { if (zend_hash_sort(target_hash, zend_qsort, array_natural_compare, 0 TSRMLS_CC) == FAILURE) { return; } } RETURN_TRUE;}/* {{{ proto void natsort(array array_arg) Sort an array using natural sort */PHP_FUNCTION(natsort){ php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);}/* }}} *//* {{{ proto void natcasesort(array array_arg) Sort an array using case-insensitive natural sort */PHP_FUNCTION(natcasesort){ php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);}/* }}} *//* {{{ proto bool asort(array array_arg [, int sort_flags]) Sort an array and maintain index association */PHP_FUNCTION(asort){ zval *array; long sort_type = SORT_REGULAR; HashTable *target_hash; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) { RETURN_FALSE; } target_hash = HASH_OF(array); set_compare_func(sort_type TSRMLS_CC); if (zend_hash_sort(target_hash, zend_qsort, array_data_compare, 0 TSRMLS_CC) == FAILURE) { RETURN_FALSE; } RETURN_TRUE;}/* }}} *//* {{{ proto bool arsort(array array_arg [, int sort_flags]) Sort an array in reverse order and maintain index association */PHP_FUNCTION(arsort){ zval *array; long sort_type = SORT_REGULAR; HashTable *target_hash; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) { RETURN_FALSE; } target_hash = HASH_OF(array); set_compare_func(sort_type TSRMLS_CC); if (zend_hash_sort(target_hash, zend_qsort, array_reverse_data_compare, 0 TSRMLS_CC) == FAILURE) { RETURN_FALSE; } RETURN_TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -