Skip to content

Commit 2de372f

Browse files
committed
Create is_countable() to check if it's safe to call count()
1 parent 1cb2536 commit 2de372f

File tree

4 files changed

+74
-0
lines changed

4 files changed

+74
-0
lines changed

ext/standard/array.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,38 @@ PHPAPI zend_long php_count_recursive(zval *array, zend_long mode) /* {{{ */
773773
}
774774
/* }}} */
775775

776+
/* {{{ proto bool is_countable(mixed var)
777+
Returns true if variable is countable using count() */
778+
PHP_FUNCTION(is_countable)
779+
{
780+
zval *array;
781+
782+
ZEND_PARSE_PARAMETERS_START(1, 1)
783+
Z_PARAM_ZVAL(array)
784+
ZEND_PARSE_PARAMETERS_END();
785+
786+
switch (Z_TYPE_P(array)) {
787+
case IS_ARRAY:
788+
RETURN_TRUE;
789+
return;
790+
case IS_OBJECT:
791+
/* first, we check if the handler is defined */
792+
if (Z_OBJ_HT_P(array)->count_elements) {
793+
RETURN_TRUE;
794+
return;
795+
}
796+
/* if not check if the object implements Countable */
797+
if (instanceof_function(Z_OBJCE_P(array), spl_ce_Countable)) {
798+
RETURN_TRUE;
799+
return;
800+
}
801+
default:
802+
RETURN_FALSE;
803+
break;
804+
}
805+
}
806+
/* }}} */
807+
776808
/* {{{ proto int count(mixed var [, int mode])
777809
Count the number of elements in a variable (usually an array) */
778810
PHP_FUNCTION(count)

ext/standard/basic_functions.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ksort, 0, 0, 1)
224224
ZEND_ARG_INFO(0, sort_flags)
225225
ZEND_END_ARG_INFO()
226226

227+
ZEND_BEGIN_ARG_INFO(arginfo_is_countable, 0)
228+
ZEND_ARG_INFO(0, var)
229+
ZEND_END_ARG_INFO()
230+
227231
ZEND_BEGIN_ARG_INFO_EX(arginfo_count, 0, 0, 1)
228232
ZEND_ARG_INFO(0, var)
229233
ZEND_ARG_INFO(0, mode)
@@ -3311,6 +3315,7 @@ const zend_function_entry basic_functions[] = { /* {{{ */
33113315
PHP_FE(shuffle, arginfo_shuffle)
33123316
PHP_FE(array_walk, arginfo_array_walk)
33133317
PHP_FE(array_walk_recursive, arginfo_array_walk_recursive)
3318+
PHP_FE(is_countable, arginfo_is_countable)
33143319
PHP_FE(count, arginfo_count)
33153320
PHP_FE(end, arginfo_end)
33163321
PHP_FE(prev, arginfo_prev)

ext/standard/php_array.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ PHP_FUNCTION(uasort);
4040
PHP_FUNCTION(uksort);
4141
PHP_FUNCTION(array_walk);
4242
PHP_FUNCTION(array_walk_recursive);
43+
PHP_FUNCTION(is_countable);
4344
PHP_FUNCTION(count);
4445
PHP_FUNCTION(end);
4546
PHP_FUNCTION(prev);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
Check if variables can be counted
3+
--FILE--
4+
<?php
5+
6+
$types = [
7+
"array" => [],
8+
"null" => null,
9+
"string" => "test",
10+
"integer" => 123,
11+
"float" => 3.14,
12+
"true" => true,
13+
"false" => false,
14+
"object" => (object) [],
15+
"simplexml" => new ArrayObject(["one", "two", "three"]),
16+
"countable" => new class implements Countable { function count() { return 1; }},
17+
];
18+
19+
foreach ($types as $type => $value) {
20+
echo "{$type}: ";
21+
var_dump(is_countable($value));
22+
}
23+
24+
?>
25+
--EXPECTF--
26+
27+
array: bool(true)
28+
null: bool(false)
29+
string: bool(false)
30+
integer: bool(false)
31+
float: bool(false)
32+
true: bool(false)
33+
false: bool(false)
34+
object: bool(false)
35+
simplexml: bool(true)
36+
countable: bool(true)

0 commit comments

Comments
 (0)