3

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

例子:

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 文件,以实现我添加的恢复功能,以便可以从上次成功完成的最后一个原子操作继续。为什么我必须这样做——环境的限制。

4

2 回答 2

8

我会这样:

$class = new ReflectionClass('Some_class_name');
$properties = array_filter($class->getProperties(), function($prop) use($class){ 
    return $prop->getDeclaringClass()->getName() == $class->getName();
});

所以基本上获取所有属性并遍历它们,检查它们是否在我们反映的类中声明。

于 2013-01-31T23:35:46.820 回答
2

虽然上述方法仅用于获取 的设置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));
    }
}
于 2013-02-01T20:54:48.230 回答