开发者

Magic methods (__get, __set) not working in extended class? [duplicate]

This question already has answers here: PHP Inherited parent method can't access child's private property (3 answers) Closed 9开发者_运维知识库 years ago.
<?php 

abstract class AbstractClass
{
    public function __get($theName)
    {
        return (isset($this->$theName)) ? $this->$theName : NULL;
    }

    public function __set($theName, $theValue)
    {
        if (false === property_exists(get_class(), $theName)) {
            throw new Exception(get_class()." does not have '".$theName."' property.");
        } else {
            $this->$theName = $theValue;
        }
    }
}

class ConcreteClass extends AbstractClass
{
        private $x;
        private $y;

        public function __construct($theX, $theY)
        {
            $this->x = $theX;
            $this->y = $theY;
        }
}

$concreteClass = new ConcreteClass(10, 20);

var_dump( $concreteClass->x );

Is there some way to amke this work or will I have to add those magic methods to the extended class?


This would work:

public function __get($theName)
{
    if(property_exists($this, $theName)) {
        $reflection = new ReflectionProperty($this, $theName);
        $reflection->setAccessible($theName);
        return $reflection->getValue($this);
    }
}

IMO, you shouldn't use __get and __set as a replacement for getters and setters. Since they are triggered when trying to access a non-accessible property, they are much more related to error-handling. And they are also much slower than a regular getter or setter.


Your problem is that the $x and $y members set in the ConcreteClass are private. Since the __get() method is defined in the parent class, it does not have the access to the child class's private members (since private members are accessible only by the class itself, not by any child or parent class). For them to be visible to the parent class, they have to be either protected or public. For your case, you'd have to use protected to maintain the magical function outside the class.

This, however, is a very odd practice at best. If the variables can be accessed via magic methods, there is no much point in making them private in the first place.


This is because your x and y belong to ConcreteClass, while parents functions only work for parents properties. For instance if you had:

abstract class AbstractClass
{
    private $x;
//...
}
class ConcreteClass extends AbstractClass
{
        private $y;

        public function __construct($theX, $theY)
    //...

then it would've worked. Parent can't access child's private properties, you must reconsider your object structure if you ran into this.

Update

As Rinuwise said you can make x and y visible by declaring them protected or public, but it's still wrong logic.

Also as an alternative you can copy-paste the __get method from AbstractClass to ConcreteClass, providing that way the parent access to private properties of its descedant; but again "you can do that" doesn't mean "you must do that":).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜