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

时间:2013-01-31 23:24:01

标签: php reflection

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

示例:

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

2 个答案:

答案 0 :(得分:8)

我会这样:

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

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

答案 1 :(得分: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));
    }
}