在PHP7.2之前,对标量值或不可计数对象使用count()
将返回1
或0
。
例如: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)
在对PHP7.2的更新中,使用上面演示的count()
将发出警告消息。
尝试计数()不可计数类型(包括sizeof()别名函数)时,将发出E_警告。
警告:count():参数必须是实现可数[sic]的数组或对象
因此,许多流行的框架将提升E_警告
,并抛出异常。
参数必须是实现可数的数组或对象
PHP开发人员也对错误提升行为进行了评论。
显示警告或将其转换为更严重错误/异常的环境将受到影响,但这应该引起对代码中错误的注意。
在PHP7.2中,如果不修改错误报告设置且不使用@count()
,如何实现不发出E_警告的
count()
的先前行为?
正如我们所讨论的,有多种方法可以实现count()
的原始功能,并且不发出E_WARNING
。
在PHP7.3中,添加了一个新函数is_countable
,专门用于解决E_警告问题,以及在代码中采用
is_数组($var)|$var instanceof\countable
的应用程序的普遍性。
在PHP7.2中,在尝试计数无法计数的事物时添加了警告。在那之后,每个人都被迫搜索和更改他们的代码,以避免它。通常,以下代码成为标准:
if(is_array($foo)||$foo instanceof可数) { // $foo是可数的}
https://wiki.php.net/rfc/is-countable
出于这个原因,解决这个问题的最佳方法似乎是执行与PHP使用的is\u countable
相同的功能,并创建一个自定义函数以确保符合count
的原始功能。
实例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;
}
结果
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
使用上述替换函数,还可以在PHP中填充
is_countable
实例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()
的功能没有改变,过去通常不会发出警告。使用自定义函数的另一种方法是使用@
错误控制运算符直接忽略警告
警告:此方法会将未定义变量视为NULL
,并且不会显示注意:未定义变量:
消息。
实例https://3v4l.org/nmWmE
@count($var);
结果
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
至于替换内部PHP函数count()
。有一个PECL扩展APD
(高级PHP调试器),它允许在核心PHP函数上使用覆盖函数
。正如扩展名所示,它在技术上是用于调试的,但对于替换自定义函数的count
的所有实例,它是一种可行的替代方法。
实例
\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;
}
问题在于,对未实现可数接口的标量或对象调用count()
会返回1,这很容易隐藏bug。
鉴于以下情况:
function handle_records(iterable $iterable)
{
if (count($iterable) === 0) {
return handle_empty();
}
foreach ($iterable as $value) {
handle_value($value);
}
}
传递一个不产生任何结果的生成器不会调用handle_empty()
也不会调用handle_value()
。
默认情况下,这仍然会返回1
,尽管还会记录一个警告。如果有的话,这个警告会引起人们对代码中潜在错误的注意。
有关更多信息,请参见计数不可数项。
你可以用"??"-运算符来解决。如果左侧为空,则使用右侧。所以当我们有一个空数组时,我们的结果将是零。
count(null ?? [])
另一种方法是将其类型化为数组。
count((array) null)