3

メソッド間で共有するために必要な多くのデータを含むpublic 配列を保持するクラスが$savedあります (以下の例)...

class Common {
    public $saved = array();

    public function setUser($data) {
        $this->saved['user_data'] = $data;
    }

    public function getUserID() {
        return $this->saved['user_data']['id'];
    }
}

このように機能するコードは、文字通り何千行もあるのです。

問題は、拡張するクラスの新しいインスタンスがCommonいくつかのメソッド内で作成されているため、それらがアクセスしたときに$saved同じデータが保持されないことです。

解決策は$saved静的変数を作成することですが、すべての参照を変更することはできない$this->savedため、コードを同一に保ちながら静的に動作させたいと考えています。

$this->savedこれが呼び出しを静的にする私の試みです...

class PropertyTest {
    private $data = array();

    public function __set($name, $value) {
        $this->data[$name] = $value;
    }

    public function __get($name) {
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }

        return null;
    }

    public function __isset($name) {
        return isset($this->data[$name]);
    }

    public function __unset($name) {
        unset($this->data[$name]);
    }
}

class Common {
    public $saved;
    private static $_instance;

    public function __construct() {
        $this->saved = self::getInstance();
    }

    public static function getInstance() {
        if (self::$_instance === null) {
            self::$_instance = new PropertyTest();
            self::$_instance->foo = array();
        }
        return self::$_instance->foo;
    }
}

静的にとどまらないように見える変数を設定すると、これはうまく機能しません(以下のテストケース)...

class Template extends Common {

    public function __construct() {
        parent::__construct();
        $this->saved['user_data'] = array('name' => 'bob');
        $user = new User();
    }
}

class User extends Common {

    public function __construct() {
        parent::__construct();
        $this->saved['user_data']['name'] .= " rocks!";
        $this->saved['user_data']['id'] = array(400, 10, 20);
    }
}

$tpl = new Template();
print_r($tpl->saved['user_data']);

$this->savedは初期化されたときに空Userであり、同じ変数ではないようです。最終的print_rには name => bob の配列のみが表示されます。

何か案は?

4

3 に答える 3

1

まず第一に、IMO、インスタンスのプロパティをクラスのプロパティとして使用するのはあまり良く$savedないと言わざるを得ません ( として宣言されていませんstaticが、その値はすべてのインスタンスと共有されます)。

これは動作中のバージョンhttp://codepad.org/8hj1MOCTで、コメント付きのコードは次のとおりです。基本的に、トリックはArrayAccess インターフェイスシングルトン パターンの両方を使用することにあります。

class Accumulator implements ArrayAccess {

    private $container = array();
    private static $instance = null;

    private function __construct() {
    }

    public function getInstance() {
        if( self::$instance === null ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function offsetSet($offset, $value) {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset) {
        return isset($this->container[$offset]);
    }

    public function offsetUnset($offset) {
        unset($this->container[$offset]);
    }

    public function offsetGet($offset) {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }

}


class Common {
    public $saved = null;


    public function __construct() {
        // initialize the "saved" object's property with the singleton
        // that variable can be used with the array syntax thanks to the ArrayAccess interface
        // so you won't have to modify your actual code
        // but also, since it's an object, this local "$this->saved" is a reference to the singleton object
        // so any change made to "$this->saved" is in reality made into the Accumulator::$instance variable
        $this->saved = Accumulator::getInstance();
    }

    public function setUser($data) {
        $this->saved['user_data'] = $data;
    }

    public function getUser() {
        return $this->saved['user_data'];
    }

}


class Template extends Common {

    // you can redeclare the variable or not. Since the property is inherited, IMO you should not redeclare it, but it works in both cases
    // public $saved = null;

    public function __construct() {
        // maybe we can move this initialization in a method in the parent class and call that method here
        $this->saved = Accumulator::getInstance();
    }

}
于 2012-05-22T17:16:36.177 に答える
0

この実装には、あなたを苦しめる可能性のある多くの問題があると思います。ただし、現在の実装では、毎回新しいインスタンスを作成しています (静的呼び出しを使用していますが)。

代わりに getInstance() をシングルトン フックとして使用し、__construct を非公開にします。これは、Common クラスのコンテキストからのみアクセスするためです。

そのようです:

class Common {
    public $saved;

    private static $_instance;

    private function __construct() {
    }

    public static function getInstance() {
        if (self::$_instance === null) {
            self::$_instance = new self();
            ... any other modifications you want to make ....
        }
        return self::$_instance;
    }
}

また、parent::_construct() を実行しないでください。代わりに、常に getInstance() メソッドを使用してください。

このシングルトン クラスを拡張するという考えを捨てることもできます。これは本当に悪いアンチパターンであり、長期的には多くの問題を引き起こす可能性があります。Common代わりに、他のクラスが読み書きできるクラスを維持するだけです。シングルトンなので、インジェクションについて心配する必要はありません。

于 2012-05-22T17:10:30.090 に答える