FtDRbwLXw6
FtDRbwLXw6

Reputation: 28889

PHP: Relationship between __isset() and __get()

I recently had a short discussion with another developer about the relationship between PHP's __isset() and __get() magic methods. It was brought about by a class that we have which lazy-loads other objects via the __get() method (lazy-loading meaning that the property doesn't exist until first accessed, at which point the object is instantiated and returned). We had differing opinions on what __isset() should return for a property that has yet to be loaded, though. The property technically doesn't exist (it isn't set, or at the very least, it's set but currently NULL), but a call to it will also technically succeed (barring any exceptions) and return a non-NULL value.

So, my question is, in this situation should __isset() simply be an indicator of whether or not __get() will succeed for the same argument (return TRUE if __get() will succeed and return a non-NULL value). Or, should it behave more technically, and return FALSE, since the data does not yet exist (even though it will when first accessed)?

A simple example:

class Foo {
    protected $data;

    public function __get($prop) {
        if ($prop == 'bar') {
            $this->data['bar'] = new Bar;
            return $this->data['bar'];
        }
    }

    public function __isset($prop) {
        if ($prop == 'bar') {
            // What goes here?
            // return isset($this->data[$prop]) would mean
            // that the first call to isset($foo->bar) below will be FALSE
            // which means that using logic like this would always fail
            // and __get() would never be called:
            // isset($foo->bar) ? $foo->bar->baz : 'foo->bar not set'
        }
    }
}

class Bar {}

$foo = new Foo;
var_dump(isset($foo->bar)); // ???
$bar = $foo->bar;
var_dump(isset($foo->bar)); // bool(true)

Upvotes: 1

Views: 1162

Answers (2)

Tim Lytle
Tim Lytle

Reputation: 17624

I think it depends on what an isset() check means to your code. What does the code using isset() actually care about?

Is it just asking of the property is value (as in, can be accessed)? Then check to see if the value can be accessed through __get() and return the result.

Is it asking if the property is valid and not null? Then actually load the value and return the result.

Is it asking if the value has been loaded? Then check if __get() has been called, and return the result.

But it should reflect the use of your class, not some arbitrary rule.

Upvotes: 0

Jon
Jon

Reputation: 437376

You have to consider this from the perspective of a user of the class. Assume that $foo is of class Foo, and you have this code:

if(isset($foo->bar)) {
    var_dump($foo->bar); // #1
}
else {
    // $foo->bar is "not set", right?
    $x = $foo->bar;
    var_dump($x); // #2
}

Rhetorical questions: would you expect #1 to ever print null? Would you expect #2 to print anything except null?

Of course not. If it worked like that, then users of class Foo would spend most of their working day cursing the author.

Assuming that I have convinced you, it's quite simple to start from the desired behavior and work back to how it should be achieved, namely to implement __isset like this:

public function __isset($prop) {
    $val = $this->$prop;
    return isset($val);
}

Upvotes: 5

Related Questions