From d0ee2a8254c69546c7191ac26cdc0499eba27acf Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Fri, 19 Jan 2018 20:01:40 -0200 Subject: [PATCH] Add is_countable function RFC: https://wiki.php.net/rfc/is-countable --- NEWS | 1 + UPGRADING | 6 ++-- Zend/zend_API.c | 17 ++++++++++ Zend/zend_API.h | 2 ++ ext/opcache/Optimizer/zend_func_info.c | 1 + ext/standard/basic_functions.c | 5 +++ ext/standard/php_type.h | 1 + .../is_countable_with_classes.phpt | 19 +++++++++++ .../is_countable_with_variables.phpt | 32 +++++++++++++++++++ ext/standard/type.c | 14 ++++++++ 10 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/general_functions/is_countable_with_classes.phpt create mode 100644 ext/standard/tests/general_functions/is_countable_with_variables.phpt diff --git a/NEWS b/NEWS index 6ab58e57ff..48a571e491 100644 --- a/NEWS +++ b/NEWS @@ -171,6 +171,7 @@ PHP NEWS . Updated bundled libsqlite to 3.22.0. (cmb) - Standard: + . Added is_countable() function. (Gabriel Caruso) . Fixed bug #75916 (DNS_CAA record results contain garbage). (Mike, Philip Sharp) . Fixed unserialize(), to disable creation of unsupported data structures diff --git a/UPGRADING b/UPGRADING index 9395cb3f35..f56c8c9235 100644 --- a/UPGRADING +++ b/UPGRADING @@ -129,8 +129,10 @@ Intl: URestrictionLevel under http://icu-project.org/apiref/icu4c/uspoof_8h.html -SPL: - . Added spl_object_id(). +Standard: + . Added is_countable() function, to check whether a value may be passed to + count(). + (RFC: https://wiki.php.net/rfc/is-countable) ======================================== 7. New Classes and Interfaces diff --git a/Zend/zend_API.c b/Zend/zend_API.c index ca68310bc9..924457916d 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -4379,6 +4379,23 @@ ZEND_API zend_bool zend_is_iterable(zval *iterable) /* {{{ */ } /* }}} */ +ZEND_API zend_bool zend_is_countable(zval *countable) /* {{{ */ +{ + switch (Z_TYPE_P(countable)) { + case IS_ARRAY: + return 1; + case IS_OBJECT: + if (Z_OBJ_HT_P(countable)->count_elements) { + return 1; + } + + return instanceof_function(Z_OBJCE_P(countable), zend_ce_countable); + default: + return 0; + } +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 132ff1cfaf..385c5f1744 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -562,6 +562,8 @@ ZEND_API const char *zend_get_object_type(const zend_class_entry *ce); ZEND_API zend_bool zend_is_iterable(zval *iterable); +ZEND_API zend_bool zend_is_countable(zval *countable); + #define add_method(arg, key, method) add_assoc_function((arg), (key), (method)) ZEND_API ZEND_FUNCTION(display_disabled_function); diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c index 2df0113b79..8ec9195511 100644 --- a/ext/opcache/Optimizer/zend_func_info.c +++ b/ext/opcache/Optimizer/zend_func_info.c @@ -610,6 +610,7 @@ static const func_info_t func_infos[] = { F0("is_object", MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline with support for incomplete class F0("is_scalar", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE), F0("is_callable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE), + F0("is_countable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE), F0("pclose", MAY_BE_FALSE | MAY_BE_LONG), F1("popen", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE), F0("readfile", MAY_BE_FALSE | MAY_BE_LONG), diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index a0ad3b3619..95281705dc 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -2586,6 +2586,10 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_is_iterable, 0, 0, 1) ZEND_ARG_INFO(0, var) ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_is_countable, 0) + ZEND_ARG_INFO(0, var) +ZEND_END_ARG_INFO() /* }}} */ /* {{{ uniqid.c */ #ifdef HAVE_GETTIMEOFDAY @@ -3111,6 +3115,7 @@ static const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(is_scalar, arginfo_is_scalar) PHP_FE(is_callable, arginfo_is_callable) PHP_FE(is_iterable, arginfo_is_iterable) + PHP_FE(is_countable, arginfo_is_countable) /* functions from file.c */ PHP_FE(pclose, arginfo_pclose) diff --git a/ext/standard/php_type.h b/ext/standard/php_type.h index 0d003f5538..845c206c1f 100644 --- a/ext/standard/php_type.h +++ b/ext/standard/php_type.h @@ -39,5 +39,6 @@ PHP_FUNCTION(is_object); PHP_FUNCTION(is_scalar); PHP_FUNCTION(is_callable); PHP_FUNCTION(is_iterable); +PHP_FUNCTION(is_countable); #endif diff --git a/ext/standard/tests/general_functions/is_countable_with_classes.phpt b/ext/standard/tests/general_functions/is_countable_with_classes.phpt new file mode 100644 index 0000000000..ebf7ac5dc9 --- /dev/null +++ b/ext/standard/tests/general_functions/is_countable_with_classes.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test is_countable() function +--CREDITS-- +Gabriel Caruso (carusogabriel34@gmail.com) +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) diff --git a/ext/standard/tests/general_functions/is_countable_with_variables.phpt b/ext/standard/tests/general_functions/is_countable_with_variables.phpt new file mode 100644 index 0000000000..700077ef17 --- /dev/null +++ b/ext/standard/tests/general_functions/is_countable_with_variables.phpt @@ -0,0 +1,32 @@ +--TEST-- +Test is_countable() function +--CREDITS-- +Gabriel Caruso (carusogabriel34@gmail.com) +--FILE-- + +--EXPECTF-- +bool(true) +bool(true) +bool(false) + +Warning: is_countable() expects exactly 1 parameter, 0 given in %s on line %d +NULL +int(2) + +Warning: count(): Parameter must be an array or an object that implements Countable in %s on line %d diff --git a/ext/standard/type.c b/ext/standard/type.c index e0a00aedcb..fff5b4eabd 100644 --- a/ext/standard/type.c +++ b/ext/standard/type.c @@ -395,6 +395,20 @@ PHP_FUNCTION(is_iterable) } /* }}} */ +/* {{{ proto bool is_countable(mixed var) + Returns true if var is countable (array or instance of Countable). */ +PHP_FUNCTION(is_countable) +{ + zval *var; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(var) + ZEND_PARSE_PARAMETERS_END(); + + RETURN_BOOL(zend_is_countable(var)); +} +/* }}} */ + /* * Local variables: * tab-width: 4 -- 2.50.1