13

在 PHP 7.2 之前,count()在标量值或不可数对象上使用会返回1or 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)

PHP 7.2+ 的更新中,如上所示使用count()将发出警告消息。

现在,当尝试 count() 不可数类型(这包括 sizeof() 别名函数)时,将发出E_WARNING

警告:count():参数必须是实现 Countable [sic]的数组或对象

结果,许多流行的框架将提升E_WARNING并抛出异常。

[ErrorException] count():参数必须是数组或实现了Countable的对象

PHP 开发人员还评论了错误提升行为。

显示警告或将其转换为更严重的错误/异常的环境会受到影响,但这只会引起对代码中错误的注意。

如何count()在 PHP 7.2+ 中实现以前的行为,即不发出E_WARNING、不修改错误报告设置且不使用@count()

4

3 回答 3

15

正如我们所讨论的,有多种方法可以实现count()而不是发出E_WARNING.

在 PHP 7.3 中添加了一个新功能is_countable,专门用于解决应用程序在其代码E_WARNING中采用的问题和普遍性。is_array($var) || $var instanceof \Countable

在 PHP 7.2 中,在尝试计算不可数事物时添加了警告。在那之后,每个人都被迫搜索和更改他们的代码,以避免它。通常,以下代码成为标准:

if (is_array($foo) || $foo instanceof Countable) { // $foo is countable }

https://wiki.php.net/rfc/is-countable


自定义函数替换

因此,解决问题的最佳方法似乎是执行与 PHP 相同的功能is_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

垫片is_countable()功能

使用上述替换函数,也可以在 中填充is_countablePHP <= 7.2因此仅在需要时使用,开销最小。

示例 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()警告

由于 的功能count()没有改变,并且过去通常不会发出警告。使用自定义函数的替代方法是使用错误控制运算符完全忽略警告@

警告:这种方法会影响将未定义的变量视为消息NULL而不显示Notice: Undefined variable: 消息。

示例 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

count()使用 APD 扩展替换

至于替换PHP内部函数count()。有一个 PECL 扩展APD(高级 PHP 调试器),它允许override_function在核心 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;
}
于 2018-09-21T13:35:08.487 回答
6

问题是调用count()未实现 Countable 接口的标量或对象返回 1,这很容易隐藏错误。

鉴于以下情况:

function handle_records(iterable $iterable)
{
    if (count($iterable) === 0) {
        return handle_empty();
    }

    foreach ($iterable as $value) {
        handle_value($value);
    }
}

传递一个不产生任何结果的生成器不会调用handle_empty()nor handle_value()
此外,没有任何迹象表明两者都没有被调用。

默认情况下,这仍然会返回1,但会另外记录一个警告。如果有的话,这个警告会引起人们对代码中潜在错误的注意。

有关详细信息,请参阅计数不可数

于 2018-04-04T23:55:21.490 回答
1

您可以使用“??”-运算符来解决它。如果左侧为空,则使用右侧。因此,当我们有一个空数组时,我们的结果将为零。

count(null ?? [])

另一种方法是将其类型转换为数组。

count((array) null)
于 2020-02-24T16:18:39.357 回答