<?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 );
Есть ли способ облегчить эту работу или мне придется добавить эти магические методы в расширенный класс?
Это будет работать:
public function __get($theName) { if(property_exists($this, $theName)) { $reflection = new ReflectionProperty($this, $theName); $reflection->setAccessible($theName); return $reflection->getValue($this); } }
IMO, вы не должны использовать __get
и __set
в качестве замены для __set
и __set
. Поскольку они срабатывают при попытке доступа к недоступному свойству, они гораздо больше связаны с обработкой ошибок. И они также намного медленнее обычного геттера или сеттера.
Ваша проблема в том, что элементы $ x и $ y, установленные в ConcreteClass
являются частными. Поскольку метод __get()
определен в родительском классе, он не имеет доступа к закрытым членам дочернего класса (поскольку частные члены доступны только самим классом, а не каким-либо дочерним или родительским классом). Чтобы они были видны родительскому классу, они должны быть либо protected
либо public
. Для вашего случая вам нужно использовать защищенный для сохранения магической функции вне класса.
Это, однако, в лучшем случае очень странная практика. Если к переменным можно получить доступ с помощью магических методов, в первую очередь их не нужно делать частным.
Это связано с тем, что ваши x
и y
принадлежат ConcreteClass
, а s functions only work for parent
parent s functions only work for parent
свойств s functions only work for parent
. Например, если у вас есть:
abstract class AbstractClass { private $x; //... } class ConcreteClass extends AbstractClass { private $y; public function __construct($theX, $theY) //...
то это сработало бы. Родитель не может получить доступ к приватным свойствам ребенка, вы должны пересмотреть свою структуру объектов, если вы столкнулись с этим.
Обновить
Поскольку Rinuwise сказал, что вы можете сделать x
и y
видимыми, объявив их защищенными или публичными, но это по-прежнему неправильная логика.
Также в качестве альтернативы вы можете скопировать-вставить метод __get
из AbstractClass в ConcreteClass, предоставив таким образом родительский доступ к закрытым свойствам своего descedant; но снова «вы можете это сделать» не означает «вы должны это сделать» :).