Search code examples
phpgettermagic-methods

using empty on inaccessible object with __isset and __get


<?php

class Magic_Methods
{
    protected $meta;

    public function __construct() 
    {
        $this->meta = (object) array(
            'test' => 1
        );
    }

    public function __isset($name) 
    {
        echo "pass isset {$name} \n";

        return isset($this->$name);
    }

    public function __get($name) 
    {
        echo "pass get {$name} \n";

        return $this->$name;
    }
}

$mm = new Magic_Methods();

$meta = empty($mm->meta->notExisting);

var_dump($meta);

echo "||\n";

$meta = empty($mm->meta);

var_dump($meta);

The snippet above does not work as expected for me. Why would the first empty() ommit the __isset? I get this:

pass get meta 
bool(true)
||
pass isset meta 
pass get meta 
bool(false)

I would expected identical results or another pass at the __isset, but not a direct call to __get. Or am I missing something here?


Solution

  • On the first call to empty, it is trying to "get" meta so it can test if "notExisting" is empty inside of meta. $meta is just a generic std class with no magic methods so you are not going to get any output (it doesn't call Magic_Methods::__get as $meta isn't an instance of Magic_Methods).

    On the second call to empty, it checks to see if meta is set, which it is and so isset returns true. As claudrian says, empty depends on the value so it then tries to "get" meta next so it can determine if the value is empty. It is not empty and so empty returns false. If you change the second call to empty, to isset, it only calls isset which returns true.