2013-01-31 77 views
3

因此,我正在使用一個設置類來擴展一個基本設置類,它將類似於「全局設置」。有幾個服務,每個服務都有自己的設置類,它擴展了抽象基本設置類。抽象基本設置類對應於服務之間共享的設置。首先,我將在下面的例子來說明,然後我會定義問題:php反射得到的屬性沒有得到基類的屬性

例如:

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

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

問題:

如果我創建一個ReflectionClass例如像這樣..

$reflect = new ReflectionClass($this); 

..從MyServiceSettings類或BaseSettings類(因爲顯然你不能有一個抽象類的實例),$reflect->getProperties() will al方式返回MyServiceSettings和BaseSettings的屬性(我猜這是合適的,因爲我們真的在使用一個具體的類)

現在我確信我可以創建一個空的類來擴展抽象BaseClass以找出哪些屬性去了哪裏(或者只是擺脫了抽象並創建了一個BaseClass的實例),但是這看起來相當混亂,所以我想知道是否有更優雅的方式來確定哪些屬性屬於父類哪些屬於孩子班?

如果你很好奇我爲什麼要這樣做 - 爲了增加恢復功能,我將序列化爲.json文件,以便可以從上次成功完成的最後一個原子操作繼續。爲什麼我必須這樣做 - 限制環境。

回答

8

我會得到這樣的:

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

所以基本上得到所有屬性,並通過他們檢查,如果他們在我們反映類被聲明迭代。

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