Prior to PHP 7.2 using count()
on a scalar value or non-countable object would return 1
or 0
.
For example: https://3v4l.org/tGRDE
var_dump(count(123)); //int(1)
var_dump(count(new stdclass)); //int(1)
var_dump(count('hello world')); //int(1)
var_dump(count(null)); //int(0)
In the updates to PHP 7.2+, using count()
as demonstrated above will emit a warning message.
An E_WARNING will now be emitted when attempting to count() non-countable types (this includes the sizeof() alias function).
Warning: count(): Parameter must be an array or an object that implements Countable [sic]
As a result many popular Frameworks will elevate the E_WARNING
and throw an Exception instead.
[ErrorException] count(): Parameter must be an array or an object that implements Countable
The error elevation behavior was also commented on by the PHP developers.
Environments that display warnings or convert them to more severe errors/exceptions would be affected, but this should just bring attention to a bug in the code.
How can the previous behavior of count()
be achieved in PHP 7.2+, that does not emit an E_WARNING
, without modifying the error reporting setting and without using @count()
?
As we discussed, there are multiple ways to achieve the original functionality of count()
and not emit an E_WARNING
.
In PHP 7.3 a new function was added is_countable
, specifically to address the E_WARNING
issue and the prevalence of applications adopting is_array($var) || $var instanceof \Countable
in their code.
In PHP 7.2, a Warning was added while trying to count uncountable things. After that, everyone was forced to search and change their code, to avoid it. Usually, the following piece of code became standard:
if (is_array($foo) || $foo instanceof Countable) { // $foo is countable }
https://wiki.php.net/rfc/is-countable
For that reason it seems the best method of resolving the issue, is to perform the same functionality that PHP is doing with is_countable
and creating a custom function to ensure compliance with the original functionality of count
.
Example https://3v4l.org/8M0Wd
function countValid($array_or_countable, $mode = \COUNT_NORMAL)
{
if (
(\PHP_VERSION_ID >= 70300 && \is_countable($array_or_countable)) ||
\is_array($array_or_countable) ||
$array_or_countable instanceof \Countable
) {
return \count($array_or_countable, $mode);
}
return null === $array_or_countable ? 0 : 1;
}
Result
array: 3
string: 1
number: 1
iterator: 3
countable: 3
zero: 1
string_zero: 1
object: 1
stdClass: 1
null: 0
empty: 1
boolt: 1
boolf: 1
Notice: Undefined variable: undefined in /in/8M0Wd on line 53
undefined: 0
is_countable()
functionUsing the above replacement function, it is also possible to shim is_countable
in PHP <= 7.2
, so it is only used when needed, with minimal overhead.
Example https://3v4l.org/i5KWH
if (!\function_exists('is_countable')) {
function is_countable($value)
{
return \is_array($value) || $value instanceof \Countable;
}
}
function countValid($array_or_countable, $mode = \COUNT_NORMAL)
{
if (\is_countable($array_or_countable)) {
return \count($array_or_countable, $mode);
}
return null === $array_or_countable ? 0 : 1;
}
count()
WarningsAs the functionality of count()
has not changed and not did not typically emit warnings in the past. An alternative to using a custom function, is to ignore the warning outright by using the @
Error Control Operator
Warning: This approach has the impact of treating undefined variables as
NULL
and not displayingNotice: Undefined variable:
message.
Example https://3v4l.org/nmWmE
@count($var);
Result
array: 3
string: 1
number: 1
iterator: 3
countable: 3
zero: 1
string_zero: 1
object: 1
stdClass: 1
null: 0
empty: 1
boolt: 1
boolf: 1
---
Undefined: 0
count()
using APD extensionAs for replacing the internal PHP function count()
. There is a PECL extension APD
(Advanced PHP Debugger), that allows for override_function
that works on core PHP functions. As the extension name suggests, it is technically meant for debugging, but is a viable alternative to replacing all instances of count
for a custom function.
Example
\rename_function('count', 'old_count');
\override_function('count', '$array_or_countable,$mode', 'return countValid($array_or_countable,$mode);');
if (!\function_exists('is_countable')) {
function is_countable($value)
{
return \is_array($value) || $value instanceof \Countable;
}
}
function countValid($array_or_countable, $mode = \COUNT_NORMAL)
{
if (\is_countable($array_or_countable)) {
return \old_count($array_or_countable, $mode);
}
return null === $array_or_countable ? 0 : 1;
}
You can solve it by using "??"-operator. If the left side is null, the right side will be used. So as we have a empty array, our result will be zero.
count(null ?? [])
Another way would be to typecast it as an array.
count((array) null)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With