]> granicus.if.org Git - php/commitdiff
Add is_countable function
authorGabriel Caruso <carusogabriel34@gmail.com>
Fri, 19 Jan 2018 22:01:40 +0000 (20:01 -0200)
committerNikita Popov <nikita.ppv@gmail.com>
Sun, 11 Mar 2018 15:41:16 +0000 (16:41 +0100)
RFC: https://wiki.php.net/rfc/is-countable

NEWS
UPGRADING
Zend/zend_API.c
Zend/zend_API.h
ext/opcache/Optimizer/zend_func_info.c
ext/standard/basic_functions.c
ext/standard/php_type.h
ext/standard/tests/general_functions/is_countable_with_classes.phpt [new file with mode: 0644]
ext/standard/tests/general_functions/is_countable_with_variables.phpt [new file with mode: 0644]
ext/standard/type.c

diff --git a/NEWS b/NEWS
index 6ab58e57ff988b2ddc378fb540646ddc3a946719..48a571e4912c2a5f8e747dc96495db4cef19a882 100644 (file)
--- 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
index 9395cb3f3585f8c60ff07e0c7d4b0a417e547a80..f56c8c9235b4a92b40f3997771088442a314f13c 100644 (file)
--- 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
index ca68310bc96858376a10a87caf3cda872b999df1..924457916d7a2186c57d7bc0fb8d98800e01f121 100644 (file)
@@ -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
index 132ff1cfaf24d8da9898fd13c5f7bb84bdac18cf..385c5f17447b94222dd03fe509ce9f77fe36d9c6 100644 (file)
@@ -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);
index 2df0113b798bff5fb04a8a4f1f2863eb62854d10..8ec91955118c303915d3a19931a3a4034ea657c5 100644 (file)
@@ -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),
index a0ad3b361982f5ffa1c020c38e68b81f7f800918..95281705dcee477139bff5b6cd790144189427e1 100644 (file)
@@ -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)
index 0d003f55383b8dc6736c69bfa4fc340f25cd498e..845c206c1ff9b3383a944b1380570a44e2242a99 100644 (file)
@@ -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 (file)
index 0000000..ebf7ac5
--- /dev/null
@@ -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 (file)
index 0000000..700077e
--- /dev/null
@@ -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
index e0a00aedcb12efa1eb0675bf72a8b5ecfd736776..fff5b4eabd62daec58436ff0891b9828d6262545 100644 (file)
@@ -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