Поэтому я работаю с классом настроек, который расширяет базовый класс настроек, который будет похож на «глобальные настройки». Существует несколько сервисов, и каждая служба имеет свой собственный класс настроек, который расширяет класс базовых настроек. Класс абстрактных базовых настроек соответствует настройкам, которые совместно используются службами. Поэтому сначала я проиллюстрирую приведенный ниже пример, а затем определю проблему:
пример:
abstract class BaseSettings { protected $settingA; protected $settingB; } class MyServiceSettings extends BaseSettings { private $settingC; public $settingD; }
проблема:
Если я создам экземпляр ReflectionClass, например …
$reflect = new ReflectionClass($this);
.. из класса MyServiceSettings или класса BaseSettings (потому что, очевидно, вы не можете иметь экземпляр абстрактного класса), $reflect->getProperties()
всегда будет возвращать свойства как MyServiceSettings, так и BaseSettings (и, я думаю, это потому что мы действительно работаем с одним конкретным классом)
Теперь я уверен, что могу создать пустой класс, который расширяет абстрактный BaseClass, чтобы выяснить, какие свойства идут туда (или просто избавиться от абстрактного и создать экземпляр BaseClass), но это кажется довольно грязным, поэтому мне интересно, есть, пожалуй, более элегантный способ определить, какие свойства принадлежат родительскому классу и которые принадлежат к дочернему классу?
Если вам интересно, почему я это делаю, я инициализирую настройки в файл .json для функции восстановления, которую я добавил, чтобы продолжить работу с последней успешной завершенной атомной операцией. Почему я должен делать это таким образом – ограничение окружающей среды.
Я бы сделал так:
$class = new ReflectionClass('Some_class_name'); $properties = array_filter($class->getProperties(), function($prop) use($class){ return $prop->getDeclaringClass()->getName() == $class->getName(); });
Таким образом, в основном получить все свойства и перебрать их, проверяя, были ли они объявлены в классе, мы отразились.
Хотя выше будет работать только для настроек MyServiceSettings
, когда вы вызываете этот метод из класса BaseSettings
, он все равно будет возвращать свойства для класса, который его расширяет (если вы имеете дело с экземпляром класса BaseSettings
где класс BaseSettings
был расширен другим классом – независимо от того, BaseSettings
класс BaseSettings
является абстрактным или конкретным), по крайней мере, когда вы ссылаетесь на базовый класс как $this
изнутри базового класса.
Возможно, есть более эффективная работа, но тот, который я нашел, – это просто использовать
$reflectionClass = new ReflectionClass(get_parent_class($this));
просто для иллюстрации примера того, как вы могли бы это использовать, вот адаптация функции, которую я использую для десериализации класса и его базового класса:
// "attribute" to be used in doc comments if it should not be // serialized / deserialized // ( remember: /** ... */ doc comments must have two asterisks!! ) private $DoNotSerialize = "[@DoNotSerialize]"; protected function dehydrate(ReflectionClass $reflectionClass) { // if you're using private or protected properties and need to use // $property->setAccessible() if(floatval(phpversion()) < 5.3) { throw new Exception("requires PHP version 5.3 or greater"); } clearstatcache(); $properties = array_filter( $reflectionClass->getProperties(ReflectionProperty::IS_PROTECTED|ReflectionProperty::IS_PUBLIC) , function($prop) use($reflectionClass) { return $prop->getDeclaringClass()->getName() == $reflectionClass->getName(); } ); $settings = null; foreach($properties as $property) { $comment = $property->getDocComment(); if( strpos($comment,$this->DoNotSerialize) !== false ){ continue; } if($property->isProtected()){ $property->setAccessible(TRUE); } if(isset($settings)) { // implementation of array_push_associative // can be found at http://php.net/manual/en/function.array-push.php array_push_associative( $settings , array($property->getName() => $property->getValue($this)) ); } else { $settings = array($property->getName() => $property->getValue($this)); } } //implementation irrelevant here writeToFile($reflectionClass->getName(), $settings); if(get_parent_class($reflectionClass)) { $this->dehydrate(get_parent_class($reflectionClass)); } }