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?

Tatu Ulmanen
źródło
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
Henrik Opel
źródło
+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.

John Magnolia
źródło
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
Loïc Février
źródło
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.

nzn
źródło
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;
    }

}
masakielastic
źródło
0

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

Raveline
źródło
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
Philippe Gerber
źródło
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
Ruel
źródło
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