Sprawdź, czy wartość jest ustawiona i null


88

Muszę sprawdzić, czy wartość jest zdefiniowana jako cokolwiek, w tym null. issettraktuje wartości null jako niezdefiniowane i zwraca false. Weźmy jako przykład:

$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

Zwróć uwagę, że $barjest to niezdefiniowane.

Muszę znaleźć warunek spełniający następujące warunki:

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

Jakieś pomysły?


19
if (isset ($ foo)) // zwraca false, spadłem z krzesła, przez te wszystkie lata ...
max4ever

in_array ($ key, array_keys ($ _ SESSION)) && is_null ($ _ SESSION [$ key]) Tak długo się nad tym zastanawiałem ..
Jack

1
To nie jest normalne zachowanie dla mnie, isset= jest ustawione?, Twoja zmienna jest ustawiona na null. Zmarnowałem dużo czasu z powodu tego ...
Vincent Decaux

Odpowiedzi:


84

IIRC, możesz użyć get_defined_vars()do tego:

$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

+1 Miałem zamiar zasugerować tę samą funkcję, get_defined_varsszczęśliwie radzi sobie z zakresem.
salathe

1
Wydaje się, że działa, ale liczyłem na coś prostszego. No cóż. Zobaczmy, czy ktoś może wymyślić jedną wkładkę.
Tatu Ulmanen

4
cóż, nie potrzebujesz vars, więc teoretycznie jest to jedna linia "if (array_key_exists ('foo', get_defined_vars ())) {}"
Hannes

Nowsza odpowiedź FVN użytkownika może być szybszy sposób, aby uzyskać zmienną, która istnieje w bieżącym kontekście, unikając kosztów z get_defined_vars(): array_key_exists('foo', compact('foo')). Lub szybciej, jeśli testowanie globalny: array_key_exists('foo', $GLOBALS).
ToolmakerSteve

25

Jeśli masz do czynienia z właściwościami obiektu, które mogą mieć wartość NULL, możesz użyć: property_exists()zamiastisset()

<?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();

?>

W przeciwieństwie do isset (), property_exists () zwraca TRUE, nawet jeśli właściwość ma wartość NULL.


11
Możesz zrobić to samo dla tablic za pomocą array_key_exists ();
teaqu

14

Zobacz Najlepszy sposób na sprawdzenie istnienia zmiennej w PHP; isset () jest wyraźnie uszkodzony

 if( array_key_exists('foo', $GLOBALS) && is_null($foo)) // true & true => true
 if( array_key_exists('bar', $GLOBALS) && is_null($bar)) // false &  => false

3
Cytowany kod działa tylko wtedy, gdy zmienna ma zasięg globalny.
Raveline,

Rzeczywiście, ale czy nie jest to najczęstszy przypadek? W funkcji będziesz mieć zmienne o zasięgu globalnym i argumenty (które są zawsze zdefiniowane). Możesz także mieć właściwości obiektu, ale wtedy możesz użyć „property_exists”.
Loïc Février

Używanie $ GLOBALS wydaje się nieco niestabilne, muszę wykonać kilka testów samodzielnie, zanim będę mógł zadeklarować, że działa.
Tatu Ulmanen

4

Odkryłem, że compactjest to funkcja, która ignoruje nieustawione zmienne, ale działa na tych ustawionych null, więc gdy masz dużą lokalną tablicę symboli, wyobrażam sobie, że możesz uzyskać bardziej wydajne rozwiązanie niż sprawdzanie array_key_exists('foo', get_defined_vars()), używając 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

Aktualizacja

Od PHP 7.3 compact () wyświetli powiadomienie o nieustawionych wartościach, więc niestety ta alternatywa nie jest już ważna.

compact () teraz generuje błąd poziomu E_NOTICE, jeśli dany łańcuch odnosi się do nieustawionej zmiennej. Dawniej takie struny były po cichu pomijane.


Ciekawa alternatywa. Ale pamiętaj, że jest to prawdopodobnie wolniejsze niż wywołanie array_key_exists na istniejącej tablicy, takiej jak $ GLOBALS - ponieważ wyszukiwanie w tablicy haszującej nie działa wolniej, gdy tabela staje się duża i dodano dodatkową pracę compact. Niemniej jednak zagłosowałem za tym, ponieważ jest to przydatne w jednej sytuacji: jeśli chcesz wiedzieć, czy fooistnieje w obecnym kontekście , niezależnie od tego, skąd pochodzi - jeśli nie obchodzi Cię, czy jest lokalny czy globalny, po prostu chcesz wiedzieć, czy to istnieje.
ToolmakerSteve

@ToolmakerSteve - tak naprawdę miałem na myśli potencjalnie znaczące narzuty związane z telefonami get_defined_vars. Zobacz tutaj .
nzn

1

Poniższy kod napisany jako rozszerzenie PHP jest odpowiednikiem array_key_exists ($ name, get_defined_vars ()) (dzięki Henrik i 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;
    }

}

0

Możesz użyć is_null i empty zamiast isset (). Pusta nie wyświetla komunikatu o błędzie, jeśli zmienna nie istnieje.


Używam is_null. Wynik jest taki sam, niezależnie od pliku isset.
Tatu Ulmanen

Popełniłem błąd podczas wysyłania mojej pierwszej odpowiedzi: czy próbowałeś z pustym ()?
Raveline,

1
To nie zadziała dla wartości, które nie są puste i nie mają wartości NULL, takich jak FALSE, 0, array () lub „”.
teaqu

1
Ta odpowiedź jest błędna. is_nullma ten sam problem co is_set: nie może rozróżnić między „nie ustawiono” i „ustawiono na wartość null”, co jest problemem, który ma OP. emptyjest jeszcze gorzej, jak wskazuje Calum.
ToolmakerSteve

0

Oto głupie obejście problemu przy użyciu 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

1
Nie wygląda na zbyt przenośnego… :)
Tatu Ulmanen

-3

is_null($bar)zwraca prawdę, ponieważ nie ma żadnych wartości. Alternatywnie możesz użyć:

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

aby sprawdzić, czy $barjest zdefiniowana i zwróci wartość true tylko wtedy, gdy:

$bar = null;
if(isset($bar) && is_null($bar)) // returns true

Nie, powiedział, że if(isset($bar))daje fałsz kiedy $bar = null.
Loïc Février

2
To nie przekaże żadnych innych zmiennych niż null (np. If $bar = "test").
Tatu Ulmanen

3
Gdy $ bar = null, isset () zwróci „false”, a is_null () zwróci wartość true. Fałsz i prawda daje zawsze fałsz.
Bartek Kosa

Ta odpowiedź jest całkowicie błędna. Jak powiedział OP, isset($bar)zwraca fałsz, nawet po $bar = null;.
ToolmakerSteve
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.