summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Caruso <carusogabriel34@gmail.com>2018-01-19 20:01:40 -0200
committerNikita Popov <nikita.ppv@gmail.com>2018-03-11 16:41:16 +0100
commitd0ee2a8254c69546c7191ac26cdc0499eba27acf (patch)
tree0607e58a4afb3b439c8f2a98b466fda472c3c33c
parent57896cf5158732101d6e09843b34f6b5f8fbba8a (diff)
downloadphp-git-d0ee2a8254c69546c7191ac26cdc0499eba27acf.tar.gz
Add is_countable function
RFC: https://wiki.php.net/rfc/is-countable
-rw-r--r--NEWS1
-rw-r--r--UPGRADING6
-rw-r--r--Zend/zend_API.c17
-rw-r--r--Zend/zend_API.h2
-rw-r--r--ext/opcache/Optimizer/zend_func_info.c1
-rw-r--r--ext/standard/basic_functions.c5
-rw-r--r--ext/standard/php_type.h1
-rw-r--r--ext/standard/tests/general_functions/is_countable_with_classes.phpt19
-rw-r--r--ext/standard/tests/general_functions/is_countable_with_variables.phpt32
-rw-r--r--ext/standard/type.c14
10 files changed, 96 insertions, 2 deletions
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--
+<?php
+var_dump(is_countable(new class extends ArrayIterator {}));
+var_dump(is_countable((array) new stdClass()));
+var_dump(is_countable(new class implements Countable {
+ public function count()
+ {
+ return count(1, 'foo');
+ }
+}));
+?>
+--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--
+<?php
+var_dump(is_countable([1, 2, 3]));
+var_dump(is_countable((array) 1));
+var_dump(is_countable((object) ['foo', 'bar', 'baz']));
+var_dump(is_countable());
+
+$foo = ['', []];
+
+if (is_countable($foo)) {
+ var_dump(count($foo));
+}
+
+$bar = null;
+if (!is_countable($bar)) {
+ count($bar);
+}
+?>
+--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