diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 6135ace457596..0873cb9316786 100755 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -982,6 +982,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_is_array, _IS_BOOL, 0) ZEND_ARG_INFO(0, var) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_is_list, _IS_BOOL, 0) + ZEND_ARG_INFO(0, var) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_is_object, _IS_BOOL, 0) ZEND_ARG_INFO(0, var) ZEND_END_ARG_INFO() @@ -1539,6 +1543,7 @@ static const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(is_numeric, arginfo_is_numeric) PHP_FE(is_string, arginfo_is_string) PHP_FE(is_array, arginfo_is_array) + PHP_FE(is_list, arginfo_is_list) PHP_FE(is_object, arginfo_is_object) PHP_FE(is_scalar, arginfo_is_scalar) PHP_FE(is_callable, arginfo_is_callable) diff --git a/ext/standard/php_type.h b/ext/standard/php_type.h index be056201dbfb9..612d0de408b2d 100644 --- a/ext/standard/php_type.h +++ b/ext/standard/php_type.h @@ -31,6 +31,7 @@ PHP_FUNCTION(is_float); PHP_FUNCTION(is_numeric); PHP_FUNCTION(is_string); PHP_FUNCTION(is_array); +PHP_FUNCTION(is_list); PHP_FUNCTION(is_object); PHP_FUNCTION(is_scalar); PHP_FUNCTION(is_callable); diff --git a/ext/standard/tests/general_functions/is_list.phpt b/ext/standard/tests/general_functions/is_list.phpt new file mode 100644 index 0000000000000..db20df1584dfb --- /dev/null +++ b/ext/standard/tests/general_functions/is_list.phpt @@ -0,0 +1,94 @@ +--TEST-- +Test is_list() function +--FILE-- + 1]); +test_is_list("mixed keys", [0 => 0, "a" => 1]); +test_is_list("ordered keys", [0 => 0, 1 => 1]); +test_is_list("shuffled keys", [1 => 0, 0 => 1]); +test_is_list("skipped keys", [0 => 0, 2 => 2]); + +$arr = [1, 2, 3]; +unset($arr[0]); +test_is_list("unset first", $arr); + +$arr = [1, 2, 3]; +unset($arr[1]); +test_is_list("unset middle", $arr); + +$arr = [1, 2, 3]; +unset($arr[2]); +test_is_list("unset end", $arr); + +$arr = [1, "a" => "a", 2]; +unset($arr["a"]); +test_is_list("unset string key", $arr); + +$arr = [1 => 1, 0 => 0]; +unset($arr[1]); +test_is_list("unset into order", $arr); + +$arr = ["a" => 1]; +unset($arr["a"]); +test_is_list("unset to empty", $arr); + +$arr = [1, 2, 3]; +$arr[] = 4; +test_is_list("append implicit", $arr); + +$arr = [1, 2, 3]; +$arr[3] = 4; +test_is_list("append explicit", $arr); + +$arr = [1, 2, 3]; +$arr[4] = 5; +test_is_list("append with gap", $arr); + +--EXPECT-- +empty: true +one: true +two: true +three: true +four: true +ten: true +null: false +int: false +float: false +string: false +object: false +true: false +false: false +string key: false +mixed keys: false +ordered keys: true +shuffled keys: false +skipped keys: false +unset first: false +unset middle: false +unset end: true +unset string key: true +unset into order: true +unset to empty: true +append implicit: true +append explicit: true +append with gap: false diff --git a/ext/standard/type.c b/ext/standard/type.c index af847bf352ce1..c0b083137c827 100644 --- a/ext/standard/type.c +++ b/ext/standard/type.c @@ -289,6 +289,43 @@ PHP_FUNCTION(is_array) } /* }}} */ +/* {{{ proto bool is_list(mixed var) + Returns true if variable is an array whose keys are all numeric, sequential, + and start at 0 */ +PHP_FUNCTION(is_list) +{ + zval *arg; + zend_array *arrval; + zend_ulong num_idx, expected_idx = 0; + zend_string *str_idx; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(arg) + ZEND_PARSE_PARAMETERS_END(); + + if (Z_TYPE_P(arg) != IS_ARRAY) + RETURN_FALSE; + + arrval = Z_ARRVAL_P(arg); + + /* Empty arrays are lists */ + if (zend_hash_num_elements(arrval) == 0) + RETURN_TRUE; + + /* Packed arrays are lists */ + if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval)) + RETURN_TRUE; + + /* Check if the list could theoretically be repacked */ + ZEND_HASH_FOREACH_KEY(arrval, num_idx, str_idx) { + if (str_idx != NULL || num_idx != expected_idx++) + RETURN_FALSE; + } ZEND_HASH_FOREACH_END(); + + RETURN_TRUE; +} +/* }}} */ + /* {{{ proto bool is_object(mixed var) Returns true if variable is an object Warning: This function is special-cased by zend_compile.c and so is usually bypassed */