Skip to content

Promote count() warning to TypeError #6180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Zend/tests/generators/errors/count_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ $gen = gen();

try {
count($gen);
} catch (Exception $e) {
echo $e;
} catch (\TypeError $e) {
echo $e->getMessage(), PHP_EOL;
}

?>
--EXPECTF--
Warning: count(): Argument #1 ($var) must be of type Countable|array, Generator given in %s on line %d
--EXPECT--
count(): Argument #1 ($var) must be of type Countable|array, Generator given
16 changes: 6 additions & 10 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -8883,6 +8883,7 @@ ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMPVAR|CV, UNUSED)

SAVE_OPLINE();
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);

while (1) {
if (Z_TYPE_P(op1) == IS_ARRAY) {
count = zend_array_count(Z_ARRVAL_P(op1));
Expand Down Expand Up @@ -8911,20 +8912,15 @@ ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMPVAR|CV, UNUSED)
break;
}

/* If There's no handler and it doesn't implement Countable then add a warning */
count = 1;
/* If There's no handler and it doesn't implement Countable then emit a TypeError */
} else if ((OP1_TYPE & (IS_VAR|IS_CV)) != 0 && Z_TYPE_P(op1) == IS_REFERENCE) {
op1 = Z_REFVAL_P(op1);
continue;
} else if (Z_TYPE_P(op1) <= IS_NULL) {
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
count = 0;
} else {
count = 1;
} else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
zend_error(E_WARNING, "%s(): Argument #1 ($var) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1));
count = 0;
zend_type_error("%s(): Argument #1 ($var) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1));
break;
}

Expand Down
48 changes: 18 additions & 30 deletions Zend/zend_vm_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -10324,6 +10324,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CONST_

SAVE_OPLINE();
op1 = RT_CONSTANT(opline, opline->op1);

while (1) {
if (Z_TYPE_P(op1) == IS_ARRAY) {
count = zend_array_count(Z_ARRVAL_P(op1));
Expand Down Expand Up @@ -10352,20 +10353,15 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CONST_
break;
}

/* If There's no handler and it doesn't implement Countable then add a warning */
count = 1;
/* If There's no handler and it doesn't implement Countable then emit a TypeError */
} else if ((IS_CONST & (IS_VAR|IS_CV)) != 0 && Z_TYPE_P(op1) == IS_REFERENCE) {
op1 = Z_REFVAL_P(op1);
continue;
} else if (Z_TYPE_P(op1) <= IS_NULL) {
if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
count = 0;
} else {
count = 1;
} else if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
zend_error(E_WARNING, "%s(): Argument #1 ($var) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1));
count = 0;
zend_type_error("%s(): Argument #1 ($var) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1));
break;
}

Expand Down Expand Up @@ -17567,6 +17563,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_TMPVAR_UNUSED_HANDL

SAVE_OPLINE();
op1 = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC);

while (1) {
if (Z_TYPE_P(op1) == IS_ARRAY) {
count = zend_array_count(Z_ARRVAL_P(op1));
Expand Down Expand Up @@ -17595,20 +17592,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_TMPVAR_UNUSED_HANDL
break;
}

/* If There's no handler and it doesn't implement Countable then add a warning */
count = 1;
/* If There's no handler and it doesn't implement Countable then emit a TypeError */
} else if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) != 0 && Z_TYPE_P(op1) == IS_REFERENCE) {
op1 = Z_REFVAL_P(op1);
continue;
} else if (Z_TYPE_P(op1) <= IS_NULL) {
if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
count = 0;
} else {
count = 1;
} else if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
zend_error(E_WARNING, "%s(): Argument #1 ($var) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1));
count = 0;
zend_type_error("%s(): Argument #1 ($var) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1));
break;
}

Expand Down Expand Up @@ -47327,6 +47319,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CV_UNUSED_HANDLER(Z

SAVE_OPLINE();
op1 = EX_VAR(opline->op1.var);

while (1) {
if (Z_TYPE_P(op1) == IS_ARRAY) {
count = zend_array_count(Z_ARRVAL_P(op1));
Expand Down Expand Up @@ -47355,20 +47348,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_COUNT_SPEC_CV_UNUSED_HANDLER(Z
break;
}

/* If There's no handler and it doesn't implement Countable then add a warning */
count = 1;
/* If There's no handler and it doesn't implement Countable then emit a TypeError */
} else if ((IS_CV & (IS_VAR|IS_CV)) != 0 && Z_TYPE_P(op1) == IS_REFERENCE) {
op1 = Z_REFVAL_P(op1);
continue;
} else if (Z_TYPE_P(op1) <= IS_NULL) {
if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
count = 0;
} else {
count = 1;
} else if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) {
ZVAL_UNDEFINED_OP1();
}
zend_error(E_WARNING, "%s(): Argument #1 ($var) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1));
count = 0;
zend_type_error("%s(): Argument #1 ($var) must be of type Countable|array, %s given", opline->extended_value ? "sizeof" : "count", zend_zval_type_name(op1));
break;
}

Expand Down
18 changes: 3 additions & 15 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,11 +740,6 @@ PHP_FUNCTION(count)
}

switch (Z_TYPE_P(array)) {
case IS_NULL:
/* Intentionally not converted to an exception */
php_error_docref(NULL, E_WARNING, "%s(): Argument #1 ($var) must be of type Countable|array, %s given", get_active_function_name(), zend_zval_type_name(array));
RETURN_LONG(0);
break;
case IS_ARRAY:
if (mode != COUNT_RECURSIVE) {
cnt = zend_array_count(Z_ARRVAL_P(array));
Expand Down Expand Up @@ -774,18 +769,11 @@ PHP_FUNCTION(count)
}
return;
}

/* If There's no handler and it doesn't implement Countable then add a warning */
/* Intentionally not converted to an exception */
php_error_docref(NULL, E_WARNING, "%s(): Argument #1 ($var) must be of type Countable|array, %s given", get_active_function_name(), zend_zval_type_name(array));
RETURN_LONG(1);
break;
}
/* fallthrough */
default:
/* Intentionally not converted to an exception */
php_error_docref(NULL, E_WARNING, "%s(): Argument #1 ($var) must be of type Countable|array, %s given", get_active_function_name(), zend_zval_type_name(array));
RETURN_LONG(1);
break;
zend_argument_type_error(1, "must be of type Countable|array, %s given", zend_zval_type_name(array));
RETURN_THROWS();
}
}
/* }}} */
Expand Down
82 changes: 48 additions & 34 deletions ext/standard/tests/array/count_invalid.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,54 @@ Only arrays and countable objects can be counted
--FILE--
<?php

$result = count(null);
var_dump($result);

$result = count("string");
var_dump($result);

$result = count(123);
var_dump($result);

$result = count(true);
var_dump($result);

$result = count(false);
var_dump($result);

$result = count((object) []);
var_dump($result);
try {
$result = count(null);
var_dump($result);
} catch (\TypeError $e) {
echo $e->getMessage() . \PHP_EOL;
}

try {
$result = count("string");
var_dump($result);
} catch (\TypeError $e) {
echo $e->getMessage() . \PHP_EOL;
}

try {
$result = count(123);
var_dump($result);
} catch (\TypeError $e) {
echo $e->getMessage() . \PHP_EOL;
}

try {
$result = count(true);
var_dump($result);
} catch (\TypeError $e) {
echo $e->getMessage() . \PHP_EOL;
}

try {
$result = count(false);
var_dump($result);
} catch (\TypeError $e) {
echo $e->getMessage() . \PHP_EOL;
}

try {
$result = count((object) []);
var_dump($result);
} catch (\TypeError $e) {
echo $e->getMessage() . \PHP_EOL;
}

?>
--EXPECTF--
Warning: count(): Argument #1 ($var) must be of type Countable|array, null given in %s on line %d
int(0)

Warning: count(): Argument #1 ($var) must be of type Countable|array, string given in %s on line %d
int(1)

Warning: count(): Argument #1 ($var) must be of type Countable|array, int given in %s on line %d
int(1)

Warning: count(): Argument #1 ($var) must be of type Countable|array, bool given in %s on line %d
int(1)

Warning: count(): Argument #1 ($var) must be of type Countable|array, bool given in %s on line %d
int(1)
--EXPECT--
count(): Argument #1 ($var) must be of type Countable|array, null given
count(): Argument #1 ($var) must be of type Countable|array, string given
count(): Argument #1 ($var) must be of type Countable|array, int given
count(): Argument #1 ($var) must be of type Countable|array, bool given
count(): Argument #1 ($var) must be of type Countable|array, bool given
count(): Argument #1 ($var) must be of type Countable|array, stdClass given

Warning: count(): Argument #1 ($var) must be of type Countable|array, stdClass given in %s on line %d
int(1)
55 changes: 0 additions & 55 deletions ext/standard/tests/array/count_recursive.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ Test count() function
--FILE--
<?php
echo "*** Testing basic functionality of count() function ***\n";
print "-- Testing NULL --\n";
$arr = NULL;
print "COUNT_NORMAL: should be 0, is ".count($arr, COUNT_NORMAL)."\n";
print "COUNT_RECURSIVE: should be 0, is ".count($arr, COUNT_RECURSIVE)."\n";

print "-- Testing arrays --\n";
$arr = array(1, array(3, 4, array(6, array(8))));
Expand All @@ -18,12 +14,7 @@ $arr = array("a" => 1, "b" => 2, array("c" => 3, array("d" => 5)));
print "COUNT_NORMAL: should be 3, is ".count($arr, COUNT_NORMAL)."\n";
print "COUNT_RECURSIVE: should be 6, is ".count($arr, COUNT_RECURSIVE)."\n";

print "-- Testing strings --\n";
print "COUNT_NORMAL: should be 1, is ".count("string", COUNT_NORMAL)."\n";
print "COUNT_RECURSIVE: should be 1, is ".count("string", COUNT_RECURSIVE)."\n";

print "-- Testing various types with no second argument --\n";
print "COUNT_NORMAL: should be 1, is ".count("string")."\n";
print "COUNT_NORMAL: should be 2, is ".count(array("a", array("b")))."\n";

$arr = array('a'=>array(NULL, NULL, NULL), 1=>array(NULL=>1, 1=>NULL),
Expand Down Expand Up @@ -56,18 +47,6 @@ foreach ($count_array as $count_value) {
$i++;
}


/* Testing count() by passing constant with no second argument */
print "\n-- Testing count() on constants with no second argument --\n";
print "COUNT_NORMAL: should be 1, is ".count(100)."\n";
print "COUNT_NORMAL: should be 1, is ".count(-23.45)."\n";

print "\n-- Testing count() on NULL and Unset variables --\n";
print "COUNT_NORMAL: should be 0, is ".count(NULL)."\n";
print "COUNT_NORMAL: should be 1, is ".count("")."\n";
print "COUNT_NORMAL: should be 0, is ".@count($a)."\n";


print "\n-- Testing count() on an empty sub-array --\n";
$arr = array(1, array(3, 4, array()));
print "COUNT_NORMAL: should be 2, is ".count($arr, COUNT_NORMAL)."\n";
Expand Down Expand Up @@ -111,30 +90,13 @@ closedir( $resource2 );
?>
--EXPECTF--
*** Testing basic functionality of count() function ***
-- Testing NULL --

Warning: count(): count(): Argument #1 ($var) must be of type Countable|array, null given in %s on line %d
COUNT_NORMAL: should be 0, is 0

Warning: count(): count(): Argument #1 ($var) must be of type Countable|array, null given in %s on line %d
COUNT_RECURSIVE: should be 0, is 0
-- Testing arrays --
COUNT_NORMAL: should be 2, is 2
COUNT_RECURSIVE: should be 8, is 8
-- Testing hashes --
COUNT_NORMAL: should be 3, is 3
COUNT_RECURSIVE: should be 6, is 6
-- Testing strings --

Warning: count(): count(): Argument #1 ($var) must be of type Countable|array, string given in %s on line %d
COUNT_NORMAL: should be 1, is 1

Warning: count(): count(): Argument #1 ($var) must be of type Countable|array, string given in %s on line %d
COUNT_RECURSIVE: should be 1, is 1
-- Testing various types with no second argument --

Warning: count(): Argument #1 ($var) must be of type Countable|array, string given in %s on line %d
COUNT_NORMAL: should be 1, is 1
COUNT_NORMAL: should be 2, is 2
-- Testing really cool arrays --
COUNT_NORMAL: should be 3, is 3
Expand Down Expand Up @@ -173,23 +135,6 @@ COUNT_RECURSIVE is 6
COUNT_NORMAL is 4
COUNT_RECURSIVE is 7

-- Testing count() on constants with no second argument --

Warning: count(): Argument #1 ($var) must be of type Countable|array, int given in %s on line %d
COUNT_NORMAL: should be 1, is 1

Warning: count(): Argument #1 ($var) must be of type Countable|array, float given in %s on line %d
COUNT_NORMAL: should be 1, is 1

-- Testing count() on NULL and Unset variables --

Warning: count(): Argument #1 ($var) must be of type Countable|array, null given in %s on line %d
COUNT_NORMAL: should be 0, is 0

Warning: count(): Argument #1 ($var) must be of type Countable|array, string given in %s on line %d
COUNT_NORMAL: should be 1, is 1
COUNT_NORMAL: should be 0, is 0

-- Testing count() on an empty sub-array --
COUNT_NORMAL: should be 2, is 2
COUNT_RECURSIVE: should be 5, is 5
Expand Down
Loading