0

How can I return null for a property and its children keys that are not set in a class?

I can use __get to make the property to return null but I have no idea how I can do it for its children keys. Any ideas?

class MyClass
{
    public $foo;
    public $bar;

    public function __construct()
    {
        $this->bar = (object) ['tool' => 'Here we go'];   
    }

    public function __get($name)
    {
        return (isset($this->$name)) ? $this->$name : null;
    }
}

$class1 = new MyClass;
var_dump($class1->foo); // null
var_dump($class1->boo); // null
var_dump($class1->bar->tool);  // 'Here we go'
var_dump($class1->bar->mars); // Notice: Undefined property: stdClass::$mars in...

Is it possible to get null for $class1->bar->mars?

Run
  • 54,938
  • 169
  • 450
  • 748

2 Answers2

1

Instead of casting $this->bar to (object) which will be an instance of stdClass (which you have no control of), create another class to represent the data you're storing in $this->bar, and define similar __set() and __get() methods.

Example:

class KeyValuePairs {
    private $pairs;

    public function __construct( $arr = [])
    {
        $this->pairs = [];
        foreach( $arr as $k => $v) {
            $this->pairs[$k] = $v;
        }
    }

    public function __get($name)
    {
        return (isset($this->pairs[$name])) ? $this->pairs[$name] : null;
    }

    public function __set($name, $value)
    {
        $this->pairs[$name] = $value;
    }
}

Then you can change your __construct() to:

public function __construct()
{
    $this->bar = new KeyValuePairs( ['tool' => 'Here we go']);   
}

And you get:

$class1 = new MyClass;
var_dump($class1->foo); // null
var_dump($class1->boo); // null
var_dump($class1->bar->tool);  // 'Here we go'
var_dump($class1->bar->mars); // null
nickb
  • 59,313
  • 13
  • 108
  • 143
1

You cannot magically do this, and I'd suggest it's bad practice to want to write such code. Either you're working with defined data structures, or you're not. If you don't know for sure what your data structure looks like, you shouldn't directly access it like ->foo->bar->baz. Use some code instead with explicit error handling. I'd suggest:

class MyClass {

    public $values;

    public function __construct() {
        $this->values = ['tool' => 'Here we go'];   
    }

    public function get($name) {
        return array_reduce(explode('.', $name), function ($value, $key) {
            if (is_array($value) && array_key_exists($key, $value)) {
                return $value[$key];
            }
            return null;
        }, $this->values);
    }

}

$foo = new MyClass;
echo $foo->get('tool');
echo $foo->get('non.existent.key');

Obviously, using clearly defined data structures is the best alternative anyway, then you can be sure those keys exist. If you ever access a non-existent key, PHP will throw an error, as it should.

deceze
  • 510,633
  • 85
  • 743
  • 889