Vérifiez si la valeur est définie et nulle

88

Je dois vérifier si la valeur est définie comme quoi que ce soit, y compris nul. issettraite les valeurs nulles comme non définies et renvoie false. Prenons l'exemple suivant:

$foo = null;

if(isset($foo)) // returns false
if(isset($bar)) // returns false
if(isset($foo) || is_null($foo)) // returns true
if(isset($bar) || is_null($bar)) // returns true, raises a notice

Notez que ce $barn'est pas défini.

Je dois trouver une condition qui satisfait à ce qui suit:

if(something($bar)) // returns false;
if(something($foo)) // returns true;

Des idées?

Tatu Ulmanen
la source
19
if (isset ($ foo)) // renvoie false, je suis tombé de la chaise, toutes ces années ...
max4ever
in_array ($ key, array_keys ($ _ SESSION)) && is_null ($ _ SESSION [$ key]) Je me posais la question depuis si longtemps ..
Jack
1
Ce n'est pas un comportement normal pour moi, isset= est défini?, Votre variable est définie sur null. J'ai perdu beaucoup de temps à cause de celui-ci ...
Vincent Decaux

Réponses:

84

IIRC, vous pouvez utiliser get_defined_vars()pour cela:

$foo = NULL;
$vars = get_defined_vars();
if (array_key_exists('bar', $vars)) {}; // Should evaluate to FALSE
if (array_key_exists('foo', $vars)) {}; // Should evaluate to TRUE
Henrik Opel
la source
+1 J'allais suggérer la même fonction, get_defined_varss'adapte heureusement à la portée.
salathe le
1
Cela semble fonctionner, mais j'espérais quelque chose de plus simple. Tant pis. Voyons si quelqu'un peut proposer une seule ligne.
Tatu Ulmanen
4
eh bien, vous n'avez pas besoin de vars, donc en théorie, sa ligne unique "if (array_key_exists ('foo', get_defined_vars ())) {}"
Hannes
les plus récentes de SFZ réponse pourrait être un moyen plus rapide d'obtenir une variable qui existe dans le contexte actuel, en évitant le coût de get_defined_vars(): array_key_exists('foo', compact('foo')). Ou plus rapide, si vous testez global: array_key_exists('foo', $GLOBALS).
ToolmakerSteve
25

Si vous avez affaire à des propriétés d'objet qui peuvent avoir une valeur NULL, vous pouvez utiliser: property_exists()au lieu deisset()

<?php

class myClass {
    public $mine;
    private $xpto;
    static protected $test;

    function test() {
        var_dump(property_exists($this, 'xpto')); //true
    }
}

var_dump(property_exists('myClass', 'mine'));   //true
var_dump(property_exists(new myClass, 'mine')); //true
var_dump(property_exists('myClass', 'xpto'));   //true, as of PHP 5.3.0
var_dump(property_exists('myClass', 'bar'));    //false
var_dump(property_exists('myClass', 'test'));   //true, as of PHP 5.3.0
myClass::test();

?>

Contrairement à isset (), property_exists () renvoie TRUE même si la propriété a la valeur NULL.

John Magnolia
la source
11
Vous pouvez faire la même chose pour les tableaux avec array_key_exists ();
Calum du
13

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

 if( array_key_exists('foo', $GLOBALS) && is_null($foo)) // true & true => true
 if( array_key_exists('bar', $GLOBALS) && is_null($bar)) // false &  => false
Loïc Février
la source
3
Le code que vous citez ne fonctionne que si la variable est dans la portée globale.
Raveline
En effet mais n'est-ce pas le cas le plus fréquent? Dans une fonction, vous aurez des variables à portée globale et des arguments (qui sont toujours définis). Vous pouvez également avoir des propriétés d'objet, mais vous pouvez alors utiliser 'property_exists'.
Loïc Février
L'utilisation de $ GLOBALS semble un peu volatile, je dois faire quelques tests moi-même avant de pouvoir déclarer que cela fonctionne.
Tatu Ulmanen
4

J'ai trouvé que compactc'est une fonction qui ignore les variables non définies mais agit sur celles définies sur null, donc lorsque vous avez une grande table de symboles locaux, j'imagine que vous pouvez obtenir une solution plus efficace de vérification array_key_exists('foo', get_defined_vars())en utilisant array_key_exists('foo', compact('foo')):

$foo = null;
echo isset($foo) ? 'true' : 'false'; // false
echo array_key_exists('foo', compact('foo')) ? 'true' : 'false'; // true
echo isset($bar) ? 'true' : 'false'; // false
echo array_key_exists('bar', compact('bar')) ? 'true' : 'false'; // false

Mettre à jour

Depuis PHP 7.3, compact () donnera un avis pour les valeurs non définies, donc malheureusement cette alternative n'est plus valide.

compact () émet maintenant une erreur de niveau E_NOTICE si une chaîne donnée fait référence à une variable non définie. Auparavant, ces chaînes étaient ignorées en silence.

nzn
la source
Alternative intéressante. Mais notez qu'il est probablement plus lent que d'appeler array_key_exists sur un tableau existant, tel que $ GLOBALS - car une recherche dans une table de hachage ne devient pas plus lente, lorsque la table devient grande et que vous avez ajouté le travail supplémentaire de compact. Néanmoins, je l'ai voté car il est utile dans une situation: si vous voulez savoir s'il fooexiste dans le contexte actuel , peu importe d'où il vient - si vous ne vous souciez pas de savoir s'il est local ou global, vous voulez juste savoir s'il existe.
ToolmakerSteve
@ToolmakerSteve - Je faisais en fait référence à la surcharge potentiellement importante de l'appel get_defined_vars. Regardez ici .
nzn
1

Le code suivant écrit comme extension PHP est équivalent à array_key_exists ($ name, get_defined_vars ()) (merci à Henrik et Hannes).

// get_defined_vars()
// https://github.com/php/php-src/blob/master/Zend/zend_builtin_functions.c#L1777
// array_key_exists
// https://github.com/php/php-src/blob/master/ext/standard/array.c#L4393

PHP_FUNCTION(is_defined_var)
{

    char *name;
    int name_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
        return;
    }

    if (!EG(active_symbol_table)) {
        zend_rebuild_symbol_table(TSRMLS_C);
    }

    if (zend_symtable_exists(EG(active_symbol_table), name, name_len + 1)) {
        RETURN_TRUE;
    }

}
masakielastic
la source
0

Vous pouvez utiliser is_null et empty au lieu de isset (). Empty n'imprime pas de message d'erreur si la variable n'existe pas.

Raveline
la source
J'utilise is_null. Le résultat est le même quel que soit le isset.
Tatu Ulmanen
J'ai fait une erreur en publiant ma première réponse: avez-vous essayé avec empty ()?
Raveline
1
Cela ne fonctionnera pas pour les valeurs qui ne sont pas vides et non NULL telles que FALSE, 0, array () ou "".
Calum du
1
Cette réponse est fausse. is_nulla le même problème que is_set: il ne peut pas faire la distinction entre "not set" et "set to null", ce qui est le problème d'OP. emptyest encore pire, comme le souligne Calum.
ToolmakerSteve
0

Voici une solution de contournement stupide utilisant xdebug. ;-)

function is_declared($name) {
    ob_start();
    xdebug_debug_zval($name);
    $content = ob_get_clean();

    return !empty($content);
}

$foo = null;
var_dump(is_declared('foo')); // -> true

$bla = 'bla';
var_dump(is_declared('bla')); // -> true

var_dump(is_declared('bar')); // -> false
Philippe Gerber
la source
1
Ne semble pas très portable .. :)
Tatu Ulmanen
-3

is_null($bar)renvoie true, car il n'a aucune valeur du tout. Alternativement, vous pouvez utiliser:

if(isset($bar) && is_null($bar)) // returns false

pour vérifier si $barest défini et ne retournera vrai que si:

$bar = null;
if(isset($bar) && is_null($bar)) // returns true
Ruel
la source
Non, il a dit que cela if(isset($bar))donne du faux quand $bar = null.
Loïc Février
2
Cela ne passera aucune autre variable que null (par exemple, if $bar = "test").
Tatu Ulmanen
3
Quand $ bar = null, isset () retournera "false" et is_null () retournera true. Faux et vrai donne toujours faux.
Bartek Kosa
Cette réponse est complètement fausse. Comme OP l'a dit, isset($bar)renvoie false, même après $bar = null;.
ToolmakerSteve