web-dev-qa-db-ja.com

E_WARNINGを発行するcount()

PHP 7.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)

PHP 7.2 + )への更新では、上記のcount()を使用すると警告メッセージが表示されます。

E_WARNINGは、count()カウント不可の型(sizeof()エイリアス関数を含む)を試みると発行されるようになりました。

警告:count():パラメーターは、Countableを実装する配列またはオブジェクトでなければなりません [sic]

その結果、多くの一般的なフレームワークはE_WARNINGを昇格させ、代わりに例外をスローします。

[ErrorException] count():パラメーターは、Countableを実装する配列またはオブジェクトでなければなりません

エラー昇格の動作については、PHP開発者がコメントしました。

警告を表示したり、より深刻なエラー/例外に変換したりする環境は影響を受けますが、これはコードのバグに注意を向けるだけです。

count()の以前の動作は、PHP 7.2+で、E_WARNINGを出力せず、エラー報告設定を変更せず、@count()を使用せずに達成できますか?

8
Toskan

先ほど説明したように、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_を_PHP <= 7.2_にshimできるようにして、必要な場合にのみ使用し、オーバーヘッドを最小限にします。

例: 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として扱い、_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
_

内部のPHP function count()。の置き換えに関しては、PECL拡張機能APD(Advanced PHP Debugger)があります。 _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;
}
_
8
fyrye

問題は、Countableインターフェイスを実装していないスカラーまたはオブジェクトでcount()を呼び出すと1が返されるため、バグを簡単に隠すことができるということです。

次の場合:

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

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

何も生成しないGeneratorを渡すと、handle_empty()handle_value()も呼び出されません。
また、どちらも呼び出されなかったという表示もありません。

デフォルトでは、これは_1_を返しますが、さらに警告を記録します。どちらかといえば、この警告はコード内の潜在的なバグに注意を促します。

詳細については、 Counting Non-Countables を参照してください。

6
Obsidian Age