PHP 反射获取属性而不获取基类的属性


php reflection get properties without getting properties of base class

所以我正在使用一个设置类,该类扩展了一个类似于"全局设置"的基本设置类。有多个服务,每个服务都有自己的设置类,用于扩展抽象基设置类。抽象基设置类对应于在服务之间共享的设置。因此,首先我将在下面用一个例子进行说明,然后我将定义问题:

例:

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));
    }
}