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のインスタンスを処理している限り)少なくとも基本クラスを基本クラス内から参照する場合は、クラスが抽象または具象であるかどうかに関係なく、別のクラスによって拡張されます。BaseSettingsBaseSettingsBaseSettings$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 に答える