Php reflection get properties without getting base class properties

So, I'm working with a settings class that extends the base settings class, which will look like "global settings". There are several services, and each service has its own customization class that extends the base settings class. The abstract baseline class corresponds to the settings that are shared by services. So first I will illustrate with an example below and then I will define the problem:

Example:

abstract class BaseSettings {
    protected $settingA;
    protected $settingB;
}

class MyServiceSettings extends BaseSettings {
    private $settingC;
    public $settingD;
}

      

Problem:

If I create an instance of ReflectionClass for example ...

$reflect = new ReflectionClass($this);

      

.. either from the MyServiceSettings class or from the BaseSettings class (because obviously you cannot have an abstract class instance) $reflect->getProperties()

will always return properties of both MyServiceSettings and BaseSettings (and I think the appropriate one because we are really working with one specific class)

Now I'm sure I can create an empty class that extends the abstract BaseClass to figure out what properties go there (or just get rid of the abstract and instantiate the BaseClass), but that seems pretty messy, so I'm wondering if there is perhaps more an elegant way to determine which properties belong to the parent class and which belong to the child class?

If you're wondering why I'm even doing this - I'm serializing the settings to a .json file for the purpose of a restore function I added to continue with the last completed last completed atomic operation. Why should I do it this way is environment limitation.

+3


source to share


2 answers


I would do like this:

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

      



So basically get all the properties and retest them if they were declared in the class we mirrored.

+8


source


While the above will work to only get the settings for MyServiceSettings

when you call this method from a class BaseSettings

, it will still return properties for the class that extends it (if you are dealing with an instance of a class BaseSettings

where the class has BaseSettings

been extended by another class - no matter whether the class BaseSettings

is abstract or concrete), at least when you refer to the base class as $this

from the base class.

There is probably a better work around, but I found that I was just using

$reflectionClass = new ReflectionClass(get_parent_class($this));

      



just to illustrate an example of how you can use this, here is an adaptation of the function I use to deserialize a class and its base class:

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

      

+2


source







All Articles