Verifique se o valor é definido e nulo

88

Preciso verificar se o valor está definido como qualquer coisa, incluindo nulo. issettrata os valores nulos como indefinidos e retorna false. Tome o seguinte como exemplo:

$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

Observe que $baré indefinido.

Preciso encontrar uma condição que satisfaça o seguinte:

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

Alguma ideia?

Tatu Ulmanen
fonte
19
if (isset ($ foo)) // retorna falso, eu caí da cadeira, todos esses anos ...
max4ever
in_array ($ key, array_keys ($ _ SESSION)) && is_null ($ _ SESSION [$ key]) Eu estava me perguntando isso por tanto tempo ..
Jack
1
Este não é um comportamento normal para mim, isset= está definido?, Sua variável está definida como nula. Eu perdi muito tempo por causa deste ...
Vincent Decaux

Respostas:

84

IIRC, você pode usar get_defined_vars()para isso:

$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
fonte
1 Eu ia sugerir a mesma função, get_defined_varsfelizmente lida com o escopo.
Salathe
1
Parece estar funcionando, mas esperava algo mais simples. Ah bem. Vamos ver se alguém consegue criar uma linha.
Tatu Ulmanen
4
bem, você não precisa de vars, portanto, em teoria, é uma linha "if (array_key_exists ('foo', get_defined_vars ())) {}"
Hannes
resposta mais recente do FVN pode ser uma maneira mais rápida para obter uma variável que existe no contexto atual, evitando o custo de get_defined_vars(): array_key_exists('foo', compact('foo')). Ou mais rápido, se testando um mundial: array_key_exists('foo', $GLOBALS).
Toolmaker Steve
25

Se você estiver lidando com propriedades de objeto que podem ter um valor NULL, você pode usar: em property_exists()vez 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();

?>

Ao contrário de isset (), property_exists () retorna TRUE mesmo se a propriedade tiver o valor NULL.

João magnólia
fonte
11
Você pode fazer o mesmo para arrays com array_key_exists ();
Calum
13

Veja Melhor maneira de testar a existência de uma variável em PHP; isset () está claramente quebrado

 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
fonte
3
O código que você cita só funciona se a variável estiver no escopo global.
Raveline,
Sim, mas não é o caso mais frequente? Em uma função, você terá variáveis ​​no escopo global e argumentos (que são sempre definidos). Você também pode ter propriedades de objeto, mas pode usar 'property_exists'.
Loïc Février
Usar $ GLOBALS parece um pouco volátil, eu mesmo tenho que fazer alguns testes antes de declarar que está funcionando.
Tatu Ulmanen
4

Descobri que compacté uma função que ignora variáveis ​​não definidas null, mas age sobre as definidas como , então, quando você tem uma grande tabela de símbolos local, imagino que você possa obter uma solução mais eficiente em relação à verificação 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

Atualizar

A partir do PHP 7.3 compact () irá avisar sobre valores não configurados, então infelizmente esta alternativa não é mais válida.

compact () agora emite um erro de nível E_NOTICE se uma determinada string se referir a uma variável não definida. Anteriormente, essas strings eram ignoradas silenciosamente.

nzn
fonte
Alternativa interessante. Mas observe que provavelmente é mais lento do que chamar array_key_exists em uma matriz existente, como $ GLOBALS - porque uma pesquisa em uma tabela hash não fica mais lenta quando a tabela fica grande e você adicionou o trabalho extra de compact. No entanto, votei positivamente porque é útil em uma situação: se você quiser saber se fooexiste no contexto atual , independentemente de onde veio - se você não se importa se é local ou global, apenas queira saber se existe.
Toolmaker Steve
@ToolmakerSteve - Na verdade, eu estava me referindo à sobrecarga potencialmente significativa da chamada get_defined_vars. Veja aqui .
nzn
1

O seguinte código escrito como uma extensão PHP é equivalente a array_key_exists ($ name, get_defined_vars ()) (graças a Henrik e 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ástico
fonte
0

Você pode usar is_null e empty ao invés de isset (). Vazio não exibe uma mensagem de erro se a variável não existir.

Raveline
fonte
Estou usando is_null. O resultado é o mesmo, independentemente do isset.
Tatu Ulmanen
Eu cometi um erro ao postar minha primeira resposta: você tentou com empty ()?
Raveline
1
Isso não funcionará para valores que não são vazios e não NULL, como FALSE, 0, array () ou "".
Calum
1
Esta resposta está errada. is_nulltem o mesmo problema que is_set: não consegue distinguir entre "não definido" e "definido como nulo", que é o problema do OP. emptyé ainda pior, como Calum aponta.
Toolmaker Steve
0

Aqui está uma solução boba 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
fonte
1
Não parece muito portátil .. :)
Tatu Ulmanen
-3

is_null($bar)retorna verdadeiro, uma vez que não possui nenhum valor. Como alternativa, você pode usar:

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

para verificar se $barestá definido e só retornará verdadeiro se:

$bar = null;
if(isset($bar) && is_null($bar)) // returns true
Ruel
fonte
Não, ele disse que if(isset($bar))dá falso quando $bar = null.
Loïc Février
2
Isso não passará nenhuma outra variável além de null (por exemplo, if $bar = "test").
Tatu Ulmanen
3
Quando $ bar = null isset () retornará "falso" e is_null () retornará verdadeiro. Falso e verdadeiro sempre resultam em falso.
Bartek Kosa
Esta resposta está completamente errada. Como disse o OP, isset($bar)retorna falso, mesmo depois $bar = null;.
Toolmaker Steve