У меня есть базовый класс, который использует магические методы php __get и __set, чтобы иметь возможность изменять частные атрибуты в расширенном классе. Затем я построил установочные функции для соответствующих приватных атрибутов.
(похоже на то, что найдено здесь
http://www.beaconfire-red.com/epic-stuff/better-getters-and-setters-php
)
Поэтому мой дочерний класс будет выглядеть следующим образом:
class User extends BaseObject {
public $id = -1;
private $_status = "";function __construct($members = array()) {
parent::__construct($members);
}
//Setter/Getter
public function status($value = null) {
if($value) {
$this->_status = $value;
} else {
return $this->_status;
}
}
Теперь, когда я сериализую этот объект, который является методом JsonSerialize в базовом классе, сериализация будет получать только открытые атрибуты из дочернего класса (т. Е. «Id»), но не будет принимать частные атрибуты (т. Е. «_Status»)
Это функция сериализации:
public function jsonSerialize() {
$json = array();
foreach($this as $key => $value) {
$json[$key] = $value;
}
return $json;
}
Есть ли способ, как вышеуказанный метод в базовом классе может идентифицировать всех геттеров в дочернем классе, чтобы они могли быть включены в сериализацию?
Другими словами, я хочу, чтобы сериализация включала в себя «id» и «status»
Я понимаю, что могу получить все методы в классе и использовать какое-то соглашение об именах для идентификации получателя / установщика, но мне нужно, чтобы имя получателя / установщика было таким же, как и имя атрибута, т.е. _status ДОЛЖЕН иметь установщик получателя с именем status ()
так есть ли другой способ идентифицировать эти конкретные функции?
использование отражение а также ReflectionProperty :: setAccessible:
public function jsonSerialize()
{
$json = array();
$class = new ReflectionClass($this);
foreach ($class->getProperties() as $key => $value) {
$value->setAccessible(true);
$json[$value->getName()] = $value->getValue($this);
}
return $json;
}
Это для того, чтобы ответить на явный вопрос. Но я не уверен, что вы должны использовать этот дизайн для решения вашей проблемы.
Я иду с другим подходом … Я думаю, что я предпочитаю это вместо размышлений.
Но мне интересно узнать, согласны ли другие.
Я собираюсь зарегистрировать каждый метод получения / установки в дочернем классе в зависимости от того, когда к нему обращались, т.е. я буду хранить имя получателя / установки в массиве.
Во время сериализации я буду взаимодействовать не только со всеми общедоступными атрибутами, но и с зарегистрированными получателями / установщиками.
Вот когда я регистрируюсь (сохраняю имя получателя / установщика) в моем базовом классе, сохраняя его в массиве _getters.
function __set($name,$value){
if(method_exists($this, $name)){
$this->$name($value);
//save in getters list for serialization
if(!in_array($name,$this->_getters))
array_push($this->_getters,$name);
}
else{
// Getter/Setter not defined so set as property of object
$this->$name = $value;
}
}
И теперь в моей сериализации я также извлекаю любые зарегистрированные геттеры и сериализую их.
это работает хорошо!
public function jsonSerialize() {
$json = array();
//do public properties
foreach($this as $key => $value) {
$json[$key] = $value;
}
//do any getter setters
foreach($this->_getters as $key => $getter) {
$value = $this->$getter;
$json[$getter] = $value;
}
return $json;
}
Есть проблемы с этим подходом?
Может быть, немного другой подход:
public function toArray()
{
$descriptor = new \ReflectionClass(get_class($this));
/** @var \ReflectionMethod[] $methods */
$methods = $descriptor->getMethods(\ReflectionMethod::IS_PUBLIC);
$array = [];
foreach ($methods as $method) {
if (substr_compare('get', $method->getName(), 0, 3) === 0) {
$property = lcfirst(substr($method->getName(), 3));
$value = $method->invoke($this);
$array[$property] = $value;
}
}
return $array;
}
Вместо того, чтобы возвращать массив, вы также можете его сериализовать. Этот подход использует общедоступные методы получения на дочерних классах.