web-dev-qa-db-fra.com

Meilleur moyen de tester l'existence d'une variable en PHP; isset () est clairement cassé

De la isset() docs :

isset() will return FALSE if testing a variable that has been set to NULL.

En principe, isset() ne vérifie pas si la variable est définie, mais si elle est définie sur autre chose que NULL.

Dans ces conditions, quel est le meilleur moyen de vérifier l’existence d’une variable? J'ai essayé quelque chose comme:

if(isset($v) || @is_null($v))

(le @ est nécessaire pour éviter l'avertissement lorsque $v n'est pas défini) mais is_null() a un problème similaire à isset(): il renvoie TRUE sur les variables non définies! Il apparaît également que:

@($v === NULL)

fonctionne exactement comme @is_null($v), donc c'est aussi le cas.

Comment pouvons-nous vérifier de manière fiable l'existence d'une variable en PHP?


Edit: il existe clairement une différence PHP entre les variables non définies et les variables définies sur NULL:

<?php
$a = array('b' => NULL);
var_dump($a);

PHP montre que $a['b'] existe et a une valeur NULL. Si vous ajoutez:

var_dump(isset($a['b']));
var_dump(isset($a['c']));

vous pouvez voir l'ambiguïté dont je parle avec la fonction isset(). Voici le résultat de ces trois fonctions var_dump()s:

array(1) {
  ["b"]=>
  NULL
}
bool(false)
bool(false)

Autre édition: deux choses.

Un cas d'utilisation. Un tableau en cours de transformation en données d'une instruction SQL UPDATE, où les clés du tableau sont les colonnes de la table et les valeurs du tableau sont les valeurs à appliquer à chaque colonne. Toutes les colonnes de la table peuvent contenir une valeur NULL, signifiée par la transmission d'une valeur NULL dans le tableau. Vous besoin un moyen de différencier une clé de tableau qui n'existe pas et la valeur d'un tableau définie sur NULL; c'est la différence entre ne pas mettre à jour la valeur de la colonne et mettre à jour la valeur de la colonne à NULL.

Deuxièmement, La réponse de Zoredache , array_key_exists() fonctionne correctement, pour mon cas d'utilisation ci-dessus et pour toute variable globale:

<?php
$a = NULL;
var_dump(array_key_exists('a', $GLOBALS));
var_dump(array_key_exists('b', $GLOBALS));

les sorties:

bool(true)
bool(false)

Comme cela gère correctement à peu près partout, je peux voir qu'il y a une ambiguïté entre les variables inexistantes et les variables définies sur NULL, j'appelle array_key_exists() le moyen le plus simple et officiel PHP pour vraiment vérifie l'existence d'une variable.

(Le seul autre cas auquel je puisse penser concerne les propriétés de classe, pour lesquelles il existe property_exists(), qui, selon ses docs , fonctionne de manière similaire à array_key_exists() en ce sens qu'il distingue correctement le non-paramétrage et le paramètre NULL.)

182
chazomaticus

Si la variable que vous vérifiez est dans la portée globale, vous pouvez faire:

array_key_exists('v', $GLOBALS) 
94
Zoredache

Tenter de donner un aperçu des différentes discussions et réponses:

Il n’existe pas de réponse unique à la question qui puisse remplacer toutes les possibilités d’utilisation de isset. Certains cas d’utilisation sont traités par d’autres fonctions, alors que d’autres ne le sont pas. résister à l'examen, ou avoir une valeur douteuse au-delà du code de golf. Loin d'être "cassés" ou "incohérents", d'autres cas d'utilisation montrent pourquoi la réaction de isset à null est le comportement logique.

Cas d'utilisation réels (avec solutions)

1. Clés de tableau

Les tableaux peuvent être traités comme des ensembles de variables, avec unset et isset comme s'ils étaient. Cependant, puisqu'elles peuvent être itérées, comptées, etc., une valeur manquante n'est pas la même que celle dont la valeur est null.

Dans ce cas, la réponse consiste à utiliser array_key_exists() au lieu de isset().

Puisque ceci prend le tableau à vérifier en tant qu'argument de fonction, PHP continuera à générer des "notifications" si le tableau lui-même n'existe pas. Dans certains cas, on peut valablement soutenir que chaque dimension aurait dû être initialisée en premier, de sorte que la notification fait son travail. Dans les autres cas, une fonction array_key_exists "récursive", vérifiant chaque dimension du tableau à son tour, éviterait cela, mais serait fondamentalement identique à @array_key_exists. Il est également quelque peu tangent au traitement des valeurs null.

2. Propriétés de l'objet

Dans la théorie traditionnelle de la "Programmation Orientée Objet", l'encapsulation et le polymorphisme sont des propriétés clés des objets; dans une implémentation OOP basée sur les classes, comme PHP, les propriétés encapsulées sont déclarées comme faisant partie de la définition de la classe et se voient attribuer des niveaux d'accès (public, protected ou private).

Cependant, PHP vous permet également d'ajouter dynamiquement des propriétés à un objet, comme les clés d'un tableau, et certaines personnes utilisent des objets sans classe (techniquement, des instances de stdClass construit, qui n'a pas de méthode. ou fonctionnalité privée) de la même manière que les tableaux associatifs. Cela conduit à des situations dans lesquelles une fonction peut vouloir savoir si une propriété particulière a été ajoutée à l'objet qui lui est attribué.

Comme pour les clés de tableau, une solution de vérification des propriétés de l'objet est incluse dans le langage, appelé, assez raisonnablement, property_exists.

Cas d'utilisation non justifiables, avec discussion

3. register_globals et autres pollutions de l'espace de noms global

La fonctionnalité register_globals a ajouté des variables à la portée globale dont les noms étaient déterminés par les aspects de la requête HTTP (paramètres GET et POST, et les cookies). Cela peut conduire à des codes buggés et peu sûrs, raison pour laquelle il a été désactivé par défaut depuis PHP 4.2, août 20 et complètement supprimé de PHP 5.4, mars 2012 . Cependant, il est possible que certains systèmes fonctionnent toujours avec cette fonctionnalité activée ou émulée. Il est également possible de "polluer" l'espace de noms global par d'autres moyens, en utilisant le mot clé global ou le tableau $GLOBALS.

Premièrement, il est peu probable que register_globals lui-même produise de manière inattendue une variable null, car les valeurs GET, POST et cookie seront toujours des chaînes ('' retournant toujours true de isset) et les variables de la session doivent être entièrement sous le contrôle du programmeur.

Deuxièmement, la pollution d'une variable avec la valeur null n'est un problème que si cela écrase une initialisation antérieure. "Sur-écrire" une variable non initialisée avec null ne poserait problème que si un code, à un autre endroit, faisait la distinction entre les deux états. Cette possibilité est donc à elle seule un argument contre . distinction.

4. get_defined_vars et compact

Quelques fonctions rarement utilisées en PHP, telles que get_defined_vars et compact , vous permettent de traiter les noms de variables comme s'il s'agissait de clés dans un tableau. Pour les variables globales, le tableau super-global $GLOBALS autorise un accès similaire et est plus courant. Ces méthodes d'accès se comporteront différemment si une variable n'est pas définie dans la portée correspondante.

Une fois que vous avez décidé de traiter un ensemble de variables comme un tableau en utilisant l’un de ces mécanismes, vous pouvez effectuer les mêmes opérations que pour tout tableau normal. Par conséquent, voir 1.

Les fonctionnalités qui existaient uniquement pour prédire le comportement de ces fonctions (par exemple, "y aura-t-il une clé 'foo' dans le tableau renvoyé par get_defined_vars?") Sont superflues, car vous pouvez simplement exécuter la fonction et le découvrir sans aucun effet néfaste .

4a. Variables variables ($$foo)

Bien que différentes des fonctions qui transforment un ensemble de variables en un tableau associatif, la plupart des cas utilisant "variables variables" ("attribuer à une variable nommée en fonction de cette autre variable") peuvent et doivent être changé pour utiliser un tableau associatif à la place.

Fondamentalement, un nom de variable est l’étiquette donnée à une valeur par le programmeur; si vous le déterminez au moment de l'exécution, il ne s'agit pas vraiment d'une étiquette, mais d'une clé dans un magasin de valeurs-clés. Plus concrètement, en n'utilisant pas de tableau, vous perdez la capacité de compter, de parcourir, etc. il peut également devenir impossible d'avoir une variable "en dehors" du magasin clé-valeur, car elle pourrait être écrasée par $$foo.

Une fois modifié pour utiliser un tableau associatif, le code sera soumis à la solution 1. L'accès indirect à la propriété d'un objet (par exemple, $foo->$property_name) peut être résolu avec la solution 2.

5. isset est tellement plus facile à taper que array_key_exists

Je ne suis pas sûr que cela soit vraiment pertinent, mais oui, les noms de fonctions de PHP peuvent parfois être assez longs et incohérents. Apparemment, les versions préhistoriques de PHP utilisaient la longueur d'un nom de fonction comme clé de hachage. Rasmus a donc délibérément créé des noms de fonction tels que htmlspecialchars afin qu'ils aient un nombre inhabituel de caractères ...

Pourtant, au moins nous n'écrivons pas Java, hein? ;)

6. Les variables non initialisées ont un type

Le page de manuel sur les bases des variables inclut cette déclaration:

Les variables non initialisées ont une valeur par défaut de leur type en fonction du contexte dans lequel elles sont utilisées

Je ne suis pas sûr s'il existe dans le moteur de Zend une notion de "type non initialisé mais connu" ou s'il y a trop de lecture dans la déclaration.

Ce qui est clair, c’est que leur comportement n’a aucune différence pratique, car les comportements décrits sur cette page pour les variables non initialisées sont identiques au comportement d’une variable dont la valeur est null. Pour en choisir un exemple, $a et $b dans ce code aboutiront à l'entier 42:

unset($a);
$a += 42;

$b = null;
$b += 42;

(Le premier signalera une variable non déclarée dans le but de vous faire écrire un meilleur code, mais cela ne changera rien à la façon dont le code s'exécute.)

99. Détecter si une fonction a été exécutée

(en gardant celui-ci en dernier, car il est beaucoup plus long que les autres. Peut-être que je l'éditerai plus tard ...)

Considérons le code suivant:

$test_value = 'hello';
foreach ( $list_of_things as $thing ) {
    if ( some_test($thing, $test_value) ) {
        $result = some_function($thing);
    }
}
if ( isset($result) ) {
    echo 'The test passed at least once!';
}

Si some_function peut renvoyer null, il est possible que echo ne soit pas atteint même si some_test a renvoyé true. L'intention du programmeur était de détecter quand $result n'avait jamais été défini, mais PHP ne le leur permettait pas.

Cependant, cette approche pose d'autres problèmes, qui deviennent clairs si vous ajoutez une boucle externe:

foreach ( $list_of_tests as $test_value ) {
    // something's missing here...
    foreach ( $list_of_things as $thing ) {
        if ( some_test($thing, $test_value) ) {
            $result = some_function($thing);
        }
    }
    if ( isset($result) ) {
        echo 'The test passed at least once!';
    }
}

Étant donné que $result n'est jamais initialisé explicitement, il prendra une valeur lorsque le tout premier test sera réussi, rendant impossible de déterminer si les tests suivants ont réussi ou non. Il s'agit en fait d'un bogue extrêmement courant lorsque les variables ne sont pas initialisées correctement.

Pour résoudre ce problème, nous devons faire quelque chose sur la ligne où j'ai commenté qu'il manquait quelque chose. La solution la plus évidente consiste à définir $result sur une "valeur terminale" que some_function ne pourra jamais renvoyer; Si c'est null, alors le reste du code fonctionnera correctement. S'il n'y a pas de candidat naturel pour une valeur terminale parce que some_function a un type de retour extrêmement imprévisible (ce qui est probablement un mauvais signe en soi), une valeur booléenne supplémentaire, par ex. $found, pourrait être utilisé à la place.

Expérience de pensée 1: la constante very_null

PHP pourrait théoriquement fournir une constante spéciale - ainsi que null - à utiliser comme valeur terminale ici; vraisemblablement, il serait illégal de renvoyer ceci à partir d'une fonction, ou ce serait contraint à null, et il en irait probablement de même pour le passer comme argument de fonction. Cela simplifierait un peu ce cas très spécifique, mais dès que vous décidiez de reformater le code - par exemple, pour placer la boucle interne dans une fonction distincte - il deviendrait inutile. Si la constante pouvait être transmise entre des fonctions, vous ne pouviez pas garantir que some_function ne la renverrait pas; elle ne serait donc plus utile en tant que valeur de terminal universelle.

Dans ce cas, l'argument de détection des variables non initialisées se résume à l'argument de cette constante spéciale: si vous remplacez le commentaire par unset($result) et que vous le traitez différemment de $result = null, vous introduisez une "valeur" pour $result qui ne peut pas être transmise, et ne peut être détecté que par des fonctions intégrées spécifiques.

Pensée expérience deux: compteur d'affectation

Une autre façon de penser à la dernière question posée par if est la suivante: "Quelque chose a-t-il été attribué à $result?" Plutôt que de considérer cela comme une valeur spéciale de $result, vous pourriez peut-être considérer cela comme une "métadonnée" relative à la variable, un peu comme la "variable corrompue" de Perl. Ainsi, plutôt que isset, vous pouvez l’appeler has_been_assigned_to et plutôt que unset, reset_assignment_state.

Mais si oui, pourquoi s'arrêter à un booléen? Que faire si vous voulez savoir combien de fois le test a réussi; vous pouvez simplement étendre vos métadonnées à un entier et avoir get_assignment_count et reset_assignment_count...

De toute évidence, l'ajout d'une telle fonctionnalité aurait un compromis en termes de complexité et de performances de la langue, de sorte qu'il devrait être soigneusement évalué par rapport à son utilité attendue. Comme dans le cas d'une constante very_null, elle ne serait utile que dans des circonstances très restreintes et résisterait de la même manière à la refactorisation.

La question qui semble heureusement évidente est de savoir pourquoi le moteur d’exécution PHP devrait supposer à l’avance que vous souhaitez garder une trace de ces choses, plutôt que de vous laisser le faire explicitement, en utilisant du code normal.

44
IMSoP

Parfois, je me perds un peu en essayant de déterminer quelle opération de comparaison utiliser dans une situation donnée. isset() s'applique uniquement aux valeurs non initialisées ou explicitement nulles. Passer/assigner null est un excellent moyen de s'assurer qu'une comparaison logique fonctionne comme prévu.

Néanmoins, il est un peu difficile d’y réfléchir, voici donc une matrice simple comparant la manière dont différentes valeurs seront évaluées par différentes opérations:

|           | ===null | is_null | isset | empty | if/else | ternary | count>0 |
| -----     | -----   | -----   | ----- | ----- | -----   | -----   | -----   |
| $a;       | true    | true    |       | true  |         |         |         |
| null      | true    | true    |       | true  |         |         |         |
| []        |         |         | true  | true  |         |         |         |
| 0         |         |         | true  | true  |         |         | true    |
| ""        |         |         | true  | true  |         |         | true    |
| 1         |         |         | true  |       | true    | true    | true    |
| -1        |         |         | true  |       | true    | true    | true    |
| " "       |         |         | true  |       | true    | true    | true    |
| "str"     |         |         | true  |       | true    | true    | true    |
| [0,1]     |         |         | true  |       | true    | true    | true    |
| new Class |         |         | true  |       | true    | true    | true    |

Pour s'adapter à la table, j'ai un peu compressé les étiquettes:

  • $a; fait référence à une variable déclarée mais non affectée
  • tout le reste dans la première colonne fait référence à une valeur assignée, telle que:
    • $a = null;
    • $a = [];
    • $a = 0;
  • les colonnes font référence à des opérations de comparaison, telles que:
    • $a === null
    • isset($a)
    • empty($a)
    • $a ? true : false

Tous les résultats sont booléens, true est imprimé et false est omis.

Vous pouvez exécuter les tests vous-même, vérifiez ce Gist:
https://Gist.github.com/mfdj/8165967

20
Mark Fox

Vous pouvez utiliser la construction de langage compact pour tester l'existence d'une variable null. Les variables qui n'existent pas ne seront pas affichées dans le résultat, alors que les valeurs NULL seront affichées.

$x = null;
$y = 'y';

$r = compact('x', 'y', 'z');
print_r($r);

// Output:
// Array ( 
//  [x] => 
//  [y] => y 
// ) 

Dans le cas de votre exemple:

if (compact('v')) {
   // True if $v exists, even when null. 
   // False on var $v; without assignment and when $v does not exist.
}

Bien sûr, pour les variables à portée globale, vous pouvez également utiliser array_key_exists ().

B.t.w. Personnellement, j'éviterais des situations telles que le fléau où il existe une différence sémantique entre une variable inexistante et la variable ayant une valeur nulle. PHP et la plupart des autres langues ne le pensent tout simplement pas.

17
Matijs

Expliquer NULL, penser logiquement

Je suppose que la réponse évidente à tout ceci est ....__ N'initialisez pas vos variables avec la valeur NULL, mais plutôt en les considérant comme un élément pertinent par rapport à ce qu'elles sont censées devenir.

Traiter NULL correctement

NULL doit être traité comme une "valeur non-existante", ce qui est la signification de NULL . La variable ne peut pas être classée comme existant dans PHP car on ne lui a pas dit de quel type d'entité il s'agit. essayer d'être. Il se peut qu’il n’existe pas, alors PHP dit simplement "bon, ce n’est pas utile, de toute façon, et NULL est ma façon de le dire".

Une dispute

Discutons maintenant. "Mais NULL est comme dire 0 ou FALSE ou ''.

Wrong, 0-FALSE- '' sont toujours classés comme des valeurs vides, mais ils SONT spécifiés comme un type de valeur ou une réponse prédéterminée à une question.FALSEest la réponse à oui ou non, '' est la réponse au titre que quelqu'un a soumis, et 0 est la réponse à la quantité ou au temps, etc. Ils sont définis comme tels type de réponse/résultat qui les rend valides comme étant définis.

NULL est juste pas de réponse quoi que ce soit, il ne nous dit pas oui ou non, il ne nous dit pas l'heure et il ne nous dit pas qu'une chaîne vide a été soumise. C'est la logique de base pour comprendre NULL.

Résumé

Il ne s'agit pas de créer des fonctions loufoques pour contourner le problème, il s'agit simplement de changer la façon dont votre cerveau perçoit NULL. Si c'est NULL, supposons que ce n'est pas défini comme quoi que ce soit. Si vous pré-définissez des variables, définissez-les comme 0, FAUX ou "" en fonction du type d’utilisation que vous souhaitez en faire.

Ne hésitez pas à citer ceci . C'est au sommet de ma tête logique :)

15
greatbigmassive

L'existence des propriétés d'un objet peut être vérifiée par property_exists

Exemple d'un test unitaire:

function testPropertiesExist()
{
    $sl =& $this->system_log;
    $props = array('log_id',
                   'type',
                   'message',
                   'username',
                   'ip_address',
                   'date_added');

    foreach($props as $prop) {
        $this->assertTrue(property_exists($sl, $prop),
                           "Property <{$prop}> exists");
    }
}
9
Thomas

En complément de la discussion de greatbigmassive sur ce que signifie NULL , considérons ce que "l'existence d'une variable" signifie réellement.

Dans de nombreuses langues, vous devez déclarer explicitement chaque variable avant de l'utiliser; cela peut déterminer son type, mais plus important encore, il déclare son portée. Une variable "existe" partout dans sa portée, et nulle part en dehors - que ce soit une fonction entière ou un seul "bloc".

Dans son champ d'application, une variable attribue un sens à une étiquette que vous, le programmeur, avez choisie. En dehors de sa portée, cette étiquette n'a pas de sens (peu importe que vous utilisiez la même étiquette dans une autre portée).

En PHP, les variables n'ont pas besoin d'être déclarées - elles prennent vie dès que vous en avez besoin. Lorsque vous écrivez dans une variable pour la première fois, PHP alloue une entrée en mémoire pour cette variable. Si vous lisez à partir d'une variable qui n'a pas d'entrée actuellement, PHP considère que cette variable a la valeur NULL.

Cependant, les détecteurs automatiques de qualité de code vous avertiront généralement si vous utilisez une variable sans la "initialiser" au préalable. Premièrement, cela aide à détecter les fautes de frappe, telles que l’affectation à $thingId mais la lecture de $thing_id; mais deuxièmement, cela vous oblige à considérer la portée de la signification de cette variable, comme le ferait une déclaration.

Tout code qui se soucie de savoir si une variable "existe" fait partie de la portée de cette variable - qu'elle ait été initialisée ou non, vous en tant que programmeur avez donné à cette étiquette une signification à cet endroit du code. Puisque vous l'utilisez, il doit dans un certain sens "exister", et s'il existe, il doit avoir une valeur implicite; en PHP, cette valeur implicite est null.

En raison du fonctionnement de PHP, il est possible d'écrire du code qui traite l'espace de noms des variables existantes non comme une étendue d'étiquettes que vous avez donnée à une signification, mais comme une sorte de magasin de valeurs-clés. Vous pouvez, par exemple, exécuter le code suivant: $var = $_GET['var_name']; $$var = $_GET['var_value'];. Ce n'est pas parce que tu peux, que c'est une bonne idée.

Il s’avère que PHP dispose d’un bien meilleur moyen de représenter les magasins de clé-valeur, appelés tableaux associatifs. Et bien que les valeurs d'un tableau puissent être traitées comme des variables, vous pouvez également effectuer des opérations sur le tableau dans son ensemble. Si vous avez un tableau associatif, vous pouvez vérifier s'il contient une clé à l'aide de array_key_exists() . 

Vous pouvez également utiliser les objets de la même manière, en définissant dynamiquement les propriétés. Dans ce cas, vous pouvez utiliser property_exists() exactement de la même manière. Bien sûr, si vous définissez une classe, vous pouvez déclarer ses propriétés - vous pouvez même choisir entre public, private et protected scope. 

Bien qu'il existe une technique différence entre une variable (par opposition à une clé de tableau ou une propriété d'objet) qui n'a pas été initialisée (ou qui a été explicitement unset()) et dont la valeur est null, aucune Le code qui considère cette différence comme étant significatif utilise des variables d'une manière qu'elles ne sont pas censées être utilisées.

4
IMSoP

isset vérifie si la variable est définie et, dans l'affirmative, si sa valeur n'est pas NULL. À mon avis, cette dernière partie n’entre pas dans le cadre de cette fonction. Aucune solution de contournement décente ne permet de déterminer si une variable est NULL parce qu'elle n'est pas définie ou parce que il est explicitement défini sur NULL.

Voici une solution possible:

$e1 = error_get_last();
$isNULL = is_null(@$x);
$e2 = error_get_last();
$isNOTSET = $e1 != $e2;
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0

Une autre solution consiste à analyser la sortie de get_defined_vars() :

$vars = get_defined_vars();
$isNOTSET = !array_key_exists("x", $vars);
$isNULL = $isNOTSET ? true : is_null($x);
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0
3
Salman A

Je vais ajouter deux cents rapides à cela. Une des raisons pour lesquelles ce problème est source de confusion est que ce scénario semble renvoyer le même résultat avec un rapport d'erreur pas à l'état complet:

$a = null;
var_dump($a); // NULL
var_dump($b); // NULL

Vous pourriez supposer à partir de ce résultat que la différence entre $a = null et ne pas définir du tout $b n’est rien.

Erreur de démarrage signalant:

NULL

Notice: Undefined variable: b in xxx on line n
NULL

Remarque: une erreur de variable non définie a été émise, mais la valeur de sortie de var_dump est toujours NULL.

PHP a évidemment une capacité interne à faire la distinction entre une variable null et une variable non définie. Il me semble qu’il devrait y avoir une fonction intégrée pour vérifier cela.

Je pense que la réponse acceptée est bonne dans l’ensemble, mais si j’allais l’appliquer, j’écrirais un wrapper pour cela. Comme mentionné précédemment dans cette réponse , je dois admettre que je n’ai pas réellement rencontré de problème. Il semble que je me retrouve presque toujours dans un scénario dans lequel mes variables sont soit définies et définies, soit ne le sont pas (indéfini, non défini, nul, vierge, etc.). Pour ne pas dire qu'une telle situation ne se reproduira plus à l'avenir, mais comme il semble s'agir d'un problème assez particulier, je ne suis pas surpris que les développeurs de PHP ne se soient pas donné la peine de l'inclure.

2
Robbie Averill

Je ne suis pas d'accord avec votre raisonnement à propos de NULL , et affirmer que vous devez changer votre état d'esprit à propos de NULL est tout simplement étrange.

Je pense que isset () n'a pas été conçu correctement. Isset () devrait vous dire si la variable a été définie et ne devrait pas être concerné par la valeur réelle de la variable.

Que se passe-t-il si vous vérifiez les valeurs renvoyées par une base de données et si l'une des colonnes a une valeur NULL, vous voulez toujours savoir si elle existe même si la valeur est NULL ... nope ne faites pas confiance à isset () ici.

également 

$a = array ('test' => 1, 'hello' => NULL);

var_dump(isset($a['test']));   // TRUE
var_dump(isset($a['foo']));    // FALSE
var_dump(isset($a['hello']));  // FALSE

isset () aurait dû être conçu pour fonctionner comme ceci:

if(isset($var) && $var===NULL){....

de cette façon, nous laissons le programmeur vérifier les types et non pas isset (), car sa valeur est NULL - sa conception est simplement stupide.

2
Christof Coetzee

Si je lance ce qui suit:

echo '<?php echo $foo; ?>' | php

Je reçois une erreur:

PHP Notice:  Undefined variable: foo in /home/altern8/- on line 1

Si je lance ce qui suit:

echo '<?php if ( isset($foo) ) { echo $foo; } ?>' | php

Je ne comprends pas l'erreur. 

Si j'ai une variable qui devrait être définie, je fais habituellement quelque chose comme ceci.

$foo = isset($foo) ? $foo : null;

ou

if ( ! isset($foo) ) $foo = null;

Ainsi, plus tard dans le script, je peux utiliser $ foo en toute sécurité et savoir qu'il est "défini" et que sa valeur par défaut est null. Plus tard, je peux if ( is_null($foo) ) { /* ... */ } si j’ai besoin de savoir si la variable existe, même si elle est nulle.

La documentation complète isset lit un peu plus que ce qui a été initialement collé. Oui, elle retourne false pour une variable précédemment définie, mais est maintenant nulle, mais elle le renvoie également si une variable n'a pas encore été définie (jamais) et pour toute variable marquée comme non définie. Il note également que l'octet NULL ("\ 0") n'est pas considéré comme null et retournera true.

Détermine si une variable est définie.

Si une variable a été désactivée avec unset (), il ne sera plus réglé . isset () retournera FALSE si vous testez un fichier variable qui a été définie sur NULL . Notez également qu'un octet NULL ("\ 0") est pas équivalent à PHP NULL constant.

1
Beau Simensen

Essayez d'utiliser

unset($v)

Il semble que la seule fois où une variable n'est pas définie est lorsqu'elle est spécifiquement non définie ($ v). Il semble que votre sens du terme "existence" diffère de la définition de PHP. NULL existe certainement, c'est NULL.

1
Joe Phillips

Je dois dire que depuis toutes mes années de programmation PHP, je n’ai jamais rencontré de problème avec isset() renvoyant false sur une variable null. OTOH, j'ai rencontré des problèmes avec isset() échouant sur une entrée de tableau NULL - mais array_key_exists() fonctionne correctement dans ce cas.

Pour certaines comparaisons, Icon définit explicitement une variable non utilisée comme renvoyant &null. Vous devez donc utiliser le test is-null dans Icon pour rechercher également une variable non définie. Cela facilite les choses. En revanche, Visual BASIC a plusieurs états pour une variable qui n'a pas de valeur (Null, Empty, Nothing, ...), et vous devez souvent en vérifier plusieurs. Ceci est connu pour être une source de bugs.

0
staticsan

Je pense que la seule solution complète est de signaler les avis avec

error_reporting(E_ALL); // Enables E_NOTICE

Mais vous devrez corriger tous les avis générés par des variables non définies, des constantes, des clés de tableaux, des propriétés de classe, entre autres. Une fois que vous avez fait cela, vous n'aurez plus à vous soucier de la différence entre les variables nulles et non déclarées, et l'ambiguïté disparaîtra.

L'activation de notice de notification peut ne pas être une bonne alternative dans toutes les situations, mais il existe de bonnes raisons de l'activer:

Pourquoi devrais-je corriger les erreurs E_NOTICE?

Dans mon cas, cela faisait plus d’un an que je travaillais dans un projet sans cela, mais j’étais habitué à faire attention à la déclaration de variables, la transition a donc été rapide.

0
mikl

LA seule façon de savoir si une variable est définie dans l'étendue actuelle ($GLOBALS n'est pas fiable) est array_key_exists( 'var_name', get_defined_vars() ).

0
Kostas Podias

Selon le manuel PHP de la fonction empty (), "Détermine si une variable est considérée comme vide. Une variable est considérée comme vide SI ELLE N'EXISTE PAS ou si sa valeur est égale à FALSE. Empty () ne génère pas un avertissement si la variable n'existe pas. " (Je souligne.) Cela signifie que la fonction empty () devrait être considérée comme le "meilleur moyen de tester l’existence d’une variable en PHP", comme indiqué dans le titre Question.

Cependant, cela ne suffit pas, car la fonction empty () peut être trompée par une variable qui existe et est définie sur NULL.

J'interromps ma réponse précédente pour présenter quelque chose de mieux, car elle est moins encombrante que ma réponse initiale (qui suit cette interruption, pour comparer).

  function undef($dnc) //do not care what we receive
  { $inf=ob_get_contents();             //get the content of the buffer
    ob_end_clean();                     //stop buffering outputs, and empty the buffer
    if($inf>"")                         //if test associated with the call to this function had an output
    { if(false!==strpos($inf, "Undef"); //if the Word "Undefined" was part of the output
        return true;                    //tested variable is undefined
    }
    return false;                       //tested variable is not undefined
  }

Deux simples lignes de code peuvent utiliser la fonction ci-dessus pour indiquer si une variable est indéfinie:

  ob_start();                           //pass all output messages (including errors) to a buffer
  if(undef($testvar===null))            //in this case the variable being tested is $testvar

Vous pouvez suivre ces deux lignes avec n'importe quoi approprié, tel que cet exemple:

    echo("variable is undefined");
  else
    echo("variable exists, holding some value");

Je voulais mettre l'appel à ob_start () et le ($ testvar === null) à l'intérieur de la fonction, et simplement transmettre la variable à la fonction, mais cela ne fonctionne pas. Même si vous essayez d'utiliser "passer par référence" de la variable à la fonction, la variable BECOMES est définie, puis la fonction ne peut jamais détecter qu'elle était auparavant indéfinie. Ce qui est présenté ici est un compromis entre ce que je voulais faire et ce qui fonctionne réellement.

Ce qui précède implique qu’il existe un autre moyen d’éviter toujours de courir dans le message d’erreur "Variable non définie". (Nous partons du principe qu'empêcher un tel message est la raison pour laquelle vous souhaitez vérifier si une variable est indéfinie.)

   function inst(&$v) { return; }  //receive any variable passed by reference; instantiates the undefined

Appelez cette fonction avant de faire quelque chose sur votre $ testvar:

   inst($testvar);                //The function doesn't affect any value of any already-existing variable

La valeur de la variable nouvellement instanciée est définie sur null, bien sûr!

(Fin de l'interruption)

Donc, après avoir étudié et expérimenté, voici quelque chose qui fonctionnera:

 function myHndlr($en, $es, $ef, $el)
 { global $er;
   $er = (substr($es, 0, 18) == "Undefined variable");
   return;
 }

 $er = false;
 if(empty($testvar))
 { set_error_handler("myHndlr");
   ($testvar === null);
   restore_error_handler();
 }
 if($er)  // will be 1 (true) if the tested variable was not defined.
 { ; //do whatever you think is appropriate to the undefined variable
 }

L'explication: Une variable $ er est initialisée avec une valeur par défaut "pas d'erreur". Une "fonction de gestionnaire" est définie. Si la variable $ testvar (la variable que nous voulons savoir si oui ou non est indéfinie) réussit le test préliminaire de la fonction empty (), nous procédons au test plus approfondi. Nous appelons la fonction set_error_handler () pour utiliser la fonction de gestionnaire définie précédemment. Ensuite, nous effectuons une simple comparaison d’identité impliquant $ testvar, qui, s’il est non défini, déclenchera une erreur. La fonction de gestionnaire capture l'erreur et teste spécifiquement pour voir si la raison de l'erreur est le fait que la variable est indéfinie. Le résultat est placé dans la variable d'erreur d'erreur $ er, que nous pourrons ensuite tester pour faire ce que nous voulons, sachant avec certitude si $ testvar a été défini ou non. Étant donné que nous n’avons besoin de la fonction de gestionnaire que pour cet objectif limité, nous restaurons la fonction de gestion des erreurs d’origine. La fonction "myHndlr" n'a besoin d'être déclarée qu'une seule fois; l'autre code peut être copié dans les emplacements appropriés, pour $ testvar ou toute autre variable que nous voulons tester de cette façon.

0