web-dev-qa-db-fra.com

count () émettant un E_WARNING

Avant PHP 7.2 en utilisant count() sur une valeur scalaire ou un objet non dénombrable retournerait 1 Ou 0.

Par exemple: 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)

Dans le mises à jour de PHP 7.2 + , l'utilisation de count() comme illustré ci-dessus émettra un message d'avertissement.

Un E_WARNING sera désormais émis lorsque vous tentez de compter () les types non dénombrables (cela inclut la fonction d'alias sizeof ()).

Avertissement: count (): Le paramètre doit être un tableau ou un objet qui implémente Countable [sic]

En conséquence, de nombreux Frameworks populaires élèveront le E_WARNING Et lèveront une exception à la place.

[ErrorException] count (): Le paramètre doit être un tableau ou un objet qui implémente Countable

Le comportement d'élévation des erreurs a également été commenté par les développeurs PHP.

Les environnements qui affichent des avertissements ou les convertissent en erreurs/exceptions plus graves seraient affectés, mais cela devrait simplement attirer l'attention sur un bogue dans le code.

Comment le comportement précédent de count() peut-il être obtenu dans PHP 7.2+, qui n'émet pas de E_WARNING, Sans modifier le paramètre de rapport d'erreur et sans utiliser @count()?

8
Toskan

Comme nous l'avons vu, il existe plusieurs façons d'obtenir la fonctionnalité d'origine de count() et de ne pas émettre de E_WARNING.

Dans PHP 7.3, une nouvelle fonction a été ajoutée is_countable , spécifiquement pour résoudre le problème E_WARNING Et la prévalence des applications adoptant is_array($var) || $var instanceof \Countable dans leur code.

Dans PHP 7.2, un avertissement a été ajouté en essayant de compter les innombrables choses. Après cela, tout le monde a été forcé de rechercher et de modifier son code, pour l'éviter. Habituellement, le code suivant est devenu standard :

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

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

Pour cette raison, il semble que la meilleure méthode pour résoudre le problème consiste à exécuter la même fonctionnalité que PHP fait avec is_countable Et à créer une fonction personnalisée pour garantir la conformité avec l'original fonctionnalité de count.

Exemple: 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;
}

Résultats:

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

Vous permettant également de caler is_countable Dans PHP <= 7.2 Afin qu'il ne soit utilisé qu'en cas de besoin, avec un minimum de frais généraux.

Exemple: 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;
}

Comme la fonctionnalité de count() n'a pas changé et n'émettait généralement pas d'avertissements dans le passé. Une alternative à l'utilisation d'une fonction personnalisée consiste à ignorer complètement l'avertissement en utilisant le @opérateur de contrôle d'erreur

Avertissement: Cette approche a pour effet de traiter les variables non définies comme NULL et de ne pas afficher le message Notice: Undefined variable:.

Exemple: https://3v4l.org/nmWmE

@count($var);

Résultat:

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

Quant au remplacement de la fonction interne PHP fonction count(). Il existe une extension PECL APD (Advanced PHP Debugger), qui permet override_function qui fonctionne sur les fonctions de base PHP. Comme le nom de l'extension le suggère, il est techniquement destiné au débogage, mais est une alternative viable pour remplacer toutes les instances de count pour une fonction personnalisée.

\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

Le problème est que l'appel de count() sur un scalaire ou un objet qui n'implémente pas l'interface Countable renvoie 1, ce qui peut facilement masquer les bogues.

Compte tenu des éléments suivants:

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

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

Passer un générateur qui ne donne rien n'appellerait ni handle_empty() ni handle_value().
De plus, aucune indication ne serait donnée que ni l'un ni l'autre n'a été appelé.

Par défaut, cela renverra toujours 1, Mais enregistrera également un avertissement. Si quelque chose, cet avertissement attirera l'attention sur les bogues potentiels dans le code.

Voir Comptage des non-dénombrables pour plus d'informations.

6
Obsidian Age