所以我正在使用一个设置类,该类扩展了一个类似于"全局设置"的基本设置类。有多个服务,每个服务都有自己的设置类,用于扩展抽象基设置类。抽象基设置类对应于在服务之间共享的设置。因此,首先我将在下面用一个例子进行说明,然后我将定义问题:
例:
abstract class BaseSettings {
protected $settingA;
protected $settingB;
}
class MyServiceSettings extends BaseSettings {
private $settingC;
public $settingD;
}
问题:
如果我像这样创建一个反射类实例。
$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
类是抽象的还是具体的),至少当你引用时作为基类内部$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));
}
}