Skip to content

Commit

Permalink
Create is_countable() to check if it's safe to call count()
Browse files Browse the repository at this point in the history
  • Loading branch information
duncan3dc committed Nov 14, 2016
1 parent 1cb2536 commit cb31777
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
32 changes: 32 additions & 0 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,38 @@ PHPAPI zend_long php_count_recursive(zval *array, zend_long mode) /* {{{ */
}
/* }}} */

/* {{{ proto bool is_countable(mixed var)
Returns true if variable is countable using count() */
PHP_FUNCTION(is_countable)
{
zval *array;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(array)
ZEND_PARSE_PARAMETERS_END();

switch (Z_TYPE_P(array)) {
case IS_ARRAY:
RETURN_TRUE;
return;
case IS_OBJECT:
/* first, we check if the handler is defined */
if (Z_OBJ_HT_P(array)->count_elements) {
RETURN_TRUE;
return;
}
/* if not check if the object implements Countable */
if (instanceof_function(Z_OBJCE_P(array), spl_ce_Countable)) {
RETURN_TRUE;
return;
}
default:
RETURN_FALSE;
break;
}
}
/* }}} */

/* {{{ proto int count(mixed var [, int mode])
Count the number of elements in a variable (usually an array) */
PHP_FUNCTION(count)
Expand Down
5 changes: 5 additions & 0 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ksort, 0, 0, 1)
ZEND_ARG_INFO(0, sort_flags)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_is_countable, 0)
ZEND_ARG_INFO(0, var)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_count, 0, 0, 1)
ZEND_ARG_INFO(0, var)
ZEND_ARG_INFO(0, mode)
Expand Down Expand Up @@ -3311,6 +3315,7 @@ const zend_function_entry basic_functions[] = { /* {{{ */
PHP_FE(shuffle, arginfo_shuffle)
PHP_FE(array_walk, arginfo_array_walk)
PHP_FE(array_walk_recursive, arginfo_array_walk_recursive)
PHP_FE(is_countable, arginfo_is_countable)
PHP_FE(count, arginfo_count)
PHP_FE(end, arginfo_end)
PHP_FE(prev, arginfo_prev)
Expand Down
1 change: 1 addition & 0 deletions ext/standard/php_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ PHP_FUNCTION(uasort);
PHP_FUNCTION(uksort);
PHP_FUNCTION(array_walk);
PHP_FUNCTION(array_walk_recursive);
PHP_FUNCTION(is_countable);
PHP_FUNCTION(count);
PHP_FUNCTION(end);
PHP_FUNCTION(prev);
Expand Down
36 changes: 36 additions & 0 deletions ext/standard/tests/array/is_countable.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
Check if variables can be counted
--FILE--
<?php

$types = [
"array" => [],
"null" => null,
"string" => "test",
"integer" => 123,
"float" => 3.14,
"true" => true,
"false" => false,
"object" => (object) [],
"simplexml" => new SimpleXMLElement("<xml><tag1></tag1><tag2></tag2></xml>"),
"countable" => new class implements Countable { function count() { return 1; }},
];

foreach ($types as $type => $value) {
echo "{$type}: ";
var_dump(is_countable($value));
}

?>
--EXPECTF--

array: bool(true)
null: bool(false)
string: bool(false)
integer: bool(false)
float: bool(false)
true: bool(false)
false: bool(false)
object: bool(false)
simplexml: bool(true)
countable: bool(true)

0 comments on commit cb31777

Please sign in to comment.