Compruebe si el valor está establecido y es nulo

88

Necesito verificar si el valor está definido como algo, incluido nulo. issettrata los valores nulos como indefinidos y devuelve false. Tome lo siguiente como ejemplo:

$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

Tenga en cuenta que $barno está definido.

Necesito encontrar una condición que satisfaga lo siguiente:

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

¿Algunas ideas?

Tatu Ulmanen
fuente
19
if (isset ($ foo)) // devuelve falso, me caí de la silla, todos estos años ...
max4ever
in_array ($ key, array_keys ($ _ SESSION)) && is_null ($ _ SESSION [$ key]) Estuve preguntándome esto durante tanto tiempo ...
Jack
1
Este no es un comportamiento normal para mí, isset= ¿está establecido ?, su variable está establecida en nulo. Perdí mucho tiempo por esto ...
Vincent Decaux

Respuestas:

84

IIRC, puede utilizar get_defined_vars()para esto:

$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
fuente
+1 Iba a sugerir la misma función, get_defined_varsfelizmente afronta el alcance.
salathe
1
Parece estar funcionando, pero esperaba algo más simple. Oh bien. Veamos si alguien puede pensar en una sola línea.
Tatu Ulmanen
4
bueno, no necesitas vars, así que en teoría es una línea "if (array_key_exists ('foo', get_defined_vars ())) {}"
Hannes
nueva respuesta de FVN podría ser una manera más rápida de conseguir una variable que existe en el contexto actual, evitando el costo de get_defined_vars(): array_key_exists('foo', compact('foo')). O más rápido, si la prueba de un mundial: array_key_exists('foo', $GLOBALS).
ToolmakerSteve
25

Si está tratando con propiedades de objeto que podrían tener un valor de NULL, puede usar: en property_exists()lugar 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();

?>

A diferencia de isset (), property_exists () devuelve TRUE incluso si la propiedad tiene el valor NULL.

John Magnolia
fuente
11
Puede hacer lo mismo para las matrices con array_key_exists ();
Teaqu
14

Consulte Mejor forma de probar la existencia de una variable en PHP; isset () está claramente roto

 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
fuente
3
El código que cita solo funciona si la variable está en el ámbito global.
Raveline
De hecho, pero ¿no es el caso más frecuente? En una función, tendrá variables de alcance global y argumentos (que siempre están definidos). También podría tener propiedades de objeto, pero luego puede usar 'property_exists'.
Loïc Février
Usar $ GLOBALS parece un poco volátil, tengo que hacer algunas pruebas antes de poder declarar que esto funciona.
Tatu Ulmanen
4

Descubrí que compactes una función que ignora las variables no configuradas pero actúa sobre las configuradas null, por lo que cuando tiene una tabla de símbolos local grande, me imagino que puede obtener una solución más eficiente que la verificación array_key_exists('foo', get_defined_vars())usando 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

Actualizar

A partir de PHP 7.3 compact () dará un aviso de valores no establecidos, por lo que desafortunadamente esta alternativa ya no es válida.

compact () ahora emite un error de nivel E_NOTICE si una cadena dada se refiere a una variable no configurada. Anteriormente, estas cadenas se saltaban silenciosamente.

nzn
fuente
Interesante alternativa. Pero tenga en cuenta que probablemente sea más lento que llamar a array_key_exists en una matriz existente, como $ GLOBALS, porque una búsqueda en una tabla hash no se vuelve más lenta cuando la tabla se agranda y ha agregado el trabajo adicional de compact. Sin embargo, lo voté a favor porque es útil en una situación: si desea saber si fooexiste en el contexto actual , independientemente de dónde venga , si no le importa si es local o global, solo quiere saber si existe.
ToolmakerSteve
@ToolmakerSteve: en realidad me refería a la sobrecarga potencialmente significativa de llamadas get_defined_vars. Vea aquí .
nzn
1

El siguiente código escrito como extensión PHP es equivalente a array_key_exists ($ name, get_defined_vars ()) (gracias a Henrik y 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;
    }

}
masakielástica
fuente
0

Puede usar is_null y empty en lugar de isset (). Empty no imprime un mensaje de error si la variable no existe.

Raveline
fuente
Estoy usando is_null. El resultado es el mismo independientemente del isset.
Tatu Ulmanen
Cometí un error al publicar mi primera respuesta: ¿lo intentaste con vacío ()?
Raveline
1
Esto no funcionará para valores que no estén vacíos ni NULL como FALSE, 0, array () o "".
Teaqu
1
Esta respuesta es incorrecta. is_nulltiene el mismo problema que is_set: no puede distinguir entre "no establecido" y "establecido en nulo", que es el problema que tiene OP. emptyes incluso peor, como señala Calum.
ToolmakerSteve
0

Aquí hay una solución tonta usando 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
fuente
1
No parece muy portátil .. :)
Tatu Ulmanen
-3

is_null($bar)devuelve verdadero, ya que no tiene ningún valor. Alternativamente, puede utilizar:

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

para verificar si $barestá definido y solo devolverá verdadero si:

$bar = null;
if(isset($bar) && is_null($bar)) // returns true
Ruel
fuente
No, dijo que if(isset($bar))da falso cuando $bar = null.
Loïc Février
2
Esto no pasará ninguna otra variable que nula (por ejemplo, si $bar = "test").
Tatu Ulmanen
3
Cuando $ bar = null isset () devolverá "falso" y is_null () devolverá verdadero. Falso y verdadero siempre da falso.
Bartek Kosa
Esta respuesta es completamente incorrecta. Como dijo OP, isset($bar)devuelve falso, incluso después $bar = null;.
ToolmakerSteve