Magic methods (__get, __set) not working in extended class? [duplicate]
<?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 parent
s 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":).
精彩评论