Check if value isset and null
Asked Answered
H

11

110

I need to check if value is defined as anything, including null. isset treats null values as undefined and returns false. Take the following as an example:

$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

Note that $bar is undefined.

I need to find a condition that satisfies the following:

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

Any ideas?

Hertzfeld answered 27/9, 2010 at 11:18 Comment(4)
if(isset($foo)) // returns false, i fell off the chair, all these years...Idolatry
in_array($key,array_keys($_SESSION)) && is_null($_SESSION[$key]) I was wondering this for so long ..Olly
This is not a normal behave for me, isset = is set ?, your variable is set at null. I wasted lot of time because of this one...Af
@VincentDecaux it's PHP... Just an example of many more illogical things in the language...Hashish
Z
100

IIRC, you can use get_defined_vars() for this:

$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
Zehe answered 27/9, 2010 at 11:51 Comment(4)
+1 I was going to suggest the same function, get_defined_vars happily copes with scope.Dorman
Seems to be working, but I was hoping for something simpler. Oh well. Let's see if anyone can come up with a one liner.Hertzfeld
well, you don't need vars, so in theory its one line "if(array_key_exists('foo',get_defined_vars())){} "Vern
fvn's newer answer might be a quicker way to get a variable that exists in current context, avoiding the cost of get_defined_vars(): array_key_exists('foo', compact('foo')). Or faster, if testing a global: array_key_exists('foo', $GLOBALS).Gensler
B
34

If you are dealing with object properties which might have a value of NULL you can use: property_exists() instead of isset()

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

?>

As opposed with isset(), property_exists() returns TRUE even if the property has the value NULL.

Brunk answered 22/1, 2014 at 8:20 Comment(3)
You can do the same for arrays with array_key_exists();Wallasey
Yes, but it is NOT possible to use this one to see if a declared property has yet been initialised. For this you can use isset(), but then of course you have a problem with readonly properties if they have been initialised to null. I've seen people grabbing to Refelction in those cases, another solution is Try/Catch but it shouldn't be that complicated!Starstudded
Plus the fact that dynamic properties are deprecated nowadays make this method (after 9 years of being useful) not recommended.Starstudded
S
17

See Best way to test for a variable's existence in PHP; isset() is clearly broken

 if( array_key_exists('foo', $GLOBALS) && is_null($foo)) // true & true => true
 if( array_key_exists('bar', $GLOBALS) && is_null($bar)) // false &  => false
Severable answered 27/9, 2010 at 11:28 Comment(4)
The code you quote only works if the variable is in the global scope.Regulus
Indeed but isn't it the most frequent case ? In a function you will have variables at global scope and arguments (which are always defined). You could also have object properties but then you can use 'property_exists'.Shorthanded
Using $GLOBALS seems a bit volatile, I have to do some testing myself before I can declare this as working.Hertzfeld
Just a note 13 years later: do not use global variables. We've moved on, it never was a good idea to begin with.Starstudded
D
9

I found this topic when I was looking for a solution for an array. to check for the presence of an array element that contains NULL, this construction helped me

    $arr= [];
    $foo = 'foo';
    $arr[$foo]= NULL;
    if (array_key_exists('bar', $arr)) {}; // Should evaluate to FALSE
    if (array_key_exists('foo', $arr)) {}; // Should evaluate to TRUE
    if (array_key_exists($foo, $arr)) {}; // Should evaluate to TRUE
Demonetize answered 25/6, 2021 at 18:45 Comment(0)
F
6

I have found that compact is a function that ignores unset variables but does act on ones set to null, so when you have a large local symbol table I would imagine you can get a more efficient solution over checking array_key_exists('foo', get_defined_vars()) by using 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

Update

As of PHP 7.3 compact() will give a notice for unset values, so unfortunately this alternative is no longer valid.

compact() now issues an E_NOTICE level error if a given string refers to an unset variable. Formerly, such strings have been silently skipped.

Formwork answered 27/9, 2016 at 10:2 Comment(2)
Interesting alternative. But note that it is probably slower than calling array_key_exists on an existing array, such as $GLOBALS - because a look up in a hash table does not get any slower, when the table gets large, and you've added the extra work of compact. Nevertheless, I upvoted it because it is useful in one situation: if you want to know whether foo exists in the current context, regardless of where it came from - if you don't care whether is local or global, just want to know whether it exists.Gensler
@Gensler - I was actually referring to the potentially significant overhead of calling get_defined_vars. See here.Formwork
M
1

The following code written as PHP extension is equivalent to array_key_exists($name, get_defined_vars()) (thanks to Henrik and 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;
    }

}
Manet answered 27/8, 2013 at 6:39 Comment(0)
P
0

Here some silly workaround using 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
Polymath answered 27/9, 2010 at 11:31 Comment(1)
Doesn't look very portable.. :)Hertzfeld
Z
0

In my case I had the following code:

class SomeClass {

  private $cachedInstance;

  public instance()
  {
    if (! isset($this->cachedInstance)) {
      $this->cachedInstance = GetCachedInstanceFromDb(); // long operation, that could return Null if the record not found
    }

    return $this->cachedInstance;
  }
}

And it failed in a way that GetCachedInstanceFromDb() got called multiple times if it returned null. All because isset() would return false even if the property was explicitly set to Null.

So, I had to do the following changes:

  1. Declare the property with initial value set to False;

  2. Use strict (type-safe) comparison when checking for the current variable value;

class SomeClass {

  private $cachedInstance = false; // #1

  public instance()
  {
    if ($this->cachedInstance === false) { // #2
      $this->cachedInstance = GetCachedInstanceFromDb();
    }

    return $this->cachedInstance;
  }
}
Zerk answered 20/8, 2021 at 5:36 Comment(3)
if you use typed parameters, then you cannot use this solutionCostive
@YevgeniyAfanasyev with union types I can )) Just wondering if it's possible to typehint something as ObjectName|false, instead of ObjectName|boolZerk
> Just wondering if it's possible to typehint something as ObjectName|false, instead of ObjectName|bool -- And I can! It would even throw a type error if I try to assign that property a true! At least in PHP 8.3. Though, for this example it should be: protected ObjectName|**null**|false $propName = false;Zerk
R
-1

You could use is_null and empty instead of isset(). Empty doesn't print an error message if the variable doesn't exist.

Regulus answered 27/9, 2010 at 11:20 Comment(4)
I am using is_null. The result is same regardless of the isset.Hertzfeld
I made a mistake while posting my first answer : did you try with empty() ?Regulus
This won't work for values that are not empty and not NULL such as FALSE, 0, array() or "".Wallasey
This answer is wrong. is_null has the same problem as is_set: it can't distinguish between "not set" and "set to null", which is the problem OP has. empty is even worse, as Calum points out.Gensler
S
-1

At risk of being downvoted, I wouldn't even bother - clearly PHP wanted you to logically think of NULL and Undef as the same. I just ran with it - I created a function:

bool isEmpty(& $davar);

that checks for isset (handles both null and undef), "", and array(). Note that this is purposefully not dealing with falseness; just empty. The & 'reference-izer' allows the variable to be passed even though undefined without an error message, and if you check for isset and return false first, your next checks against "" and array() can be made without error.

The next function takes advantage of this function and is used where you would use

$davar || some-default.

and that is:

mixed defaultForEmpty(& $daVar, $default);

which just has the condition:

if (isEmpty($daVar)) 
    return $default;
else
    return $daVar;

BTW, these work with object references, array indexes, $_GET, $_POST, etc..

Superfine answered 18/6, 2021 at 4:7 Comment(0)
Z
-3

is_null($bar) returns true, since it has no values at all. Alternatively, you can use:

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

to check if $bar is defined and will only return true if:

$bar = null;
if(isset($bar) && is_null($bar)) // returns true
Zygospore answered 27/9, 2010 at 11:29 Comment(4)
No, he said that if(isset($bar)) gives false when $bar = null.Shorthanded
This will not pass any other variables than null (eg. if $bar = "test").Hertzfeld
When $bar = null isset() will return "false" and is_null() will return true. False and true gives always false.Lyons
This answer is completely wrong. As OP said, isset($bar) returns false, even after $bar = null;.Gensler

© 2022 - 2024 — McMap. All rights reserved.