Search code examples
phpoopmagic-methods

PHP __set and __get overloading in inheritance


I am implementing an OOP design using PHP. I wonder how PHP handles inheritance for its magic methods like __get and __set.

class Foo
{
    protected $property1;

    public function __get($name)
    {
        if ($name == "property1")
        {
            // do some logic
            return $result; // may be null
        }
        return;
    }

    public function __set($name, $value)
    {
        if ($name == "property1")
        {
            // do some logic
            return $result; // may be null
        }
        result;
    }
}

Now for extending Foo:

class Bar extends Foo
{
    protected $property2;

    public function __get($name)
    {
        if (($result = parent::__get($name)) !== null)
            return $result; // may be null
        if ($name == "property2")
        {
            // do some logic
            return $result; // may be null
        }
        return;
    }

    public function __set($name, $value)
    {
        if (($result = parent::__set($name, $value)) !== null)
            return $result; // may be null
        if ($name == "property2")
        {
            // do some logic
            return $result; // may be null
        }
        return;
    }
}

As PHP returns null as the result of a function with nothing to return... this may lead in ambiguity of whether the parent::__get() or parent::__set() returned null truely or returned with no value; and leads to overhead.

Now if PHP considers the static::_get() and static::__set() first and fall backs to the parent versions on failure, this could be simplified as:

class Bar extends Foo
{
    protected $property2;

    public function __get($name)
    {
        if ($name = "property2")
        {
            // do some logic
            return $result; // may be null
        }
        return;
    }

    public function __set($name, $value)
    {
        if ($name = "property2")
        {
            // do some logic
            return $result; // may be null
        }
        return;
    }
}

I can't test it on current implementation because the classes in context manipulates production, live database. Which is the correct implementation?

Thanks!


Solution

  • Use magic methods only as proxy methods. Your code will be much cleaner and you don't have to deal with problems caused by inheritance.

    Simple example:

    class Foo
    {
        protected $property1;
    
        public function setProperty1($property1)
        {
            // do some logic
            $this->property1 = $property1;
            return $this;
        }
    
        public function getProperty1()
        {
            // do some logic
            return $this->property1;
        }
    
        public function __get($name)
        {
            $method = 'get' . ucfirst($name);
            if (method_exists($this, $method)) {
                return $this->$method();
            }
        }
    
        public function __set($name, $value)
        {
            $method = 'set' . ucfirst($name);
            if (method_exists($this, $method)) {
                $this->$method($value);
            }
        }
    }
    
    class Bar extends Foo
    {
        protected $property2;
    
        public function setProperty2($property2)
        {
            // do some logic
            $this->property2 = $property2;
            return $this;
        }
    
        public function getProperty2()
        {
            // do some logic
            return $this->property2;
        }
    }
    

    Example call:

    $bar = new Bar;
    $bar->property1 = 'foo';
    $bar->property2 = 'bar';
    var_dump($bar);