PHP 在同一类的实例之间共享受保护的属性


PHP share protected property among instances of the same class

我想实现一个类,它缓存一些内部结果。这些结果对于类的所有实例都是相同的,即在所有实例之间共享此缓存可能是明智的。

但是,这些结果对于子类可能不同,即缓存不应与子类共享。由于缓存对于所有子类也是一个好主意,因此仍应继承该机制。但是每个子类都必须使用不同的静态数组。

我可以想到各种技巧和复杂的模式来实现这一目标,但没有一个看起来很理智。有人知道PHP中的有效模式吗?

private static变量的组合来保存所有子类的缓存数据和protected访问器函数听起来像是可以工作的,而且它并不太复杂:

class Base {
    private static $cache = array();
    protected getCacheItem($key) {
        $type = get_class($this);
        if (!isset(self::$cache[$type])) {
            self::$cache[$type] = array();
        }
        // add checks to taste
        return self::$cache[$type][$key];
    }
    protected function setCacheItem($key, $value) {
        // similar to the above
    }
}

从这里开始,您可以花哨,以便以变得有些邪恶为代价访问缓存非常方便:

class Base {
    private static $cache = array();
    // WARNING! QUESTIONABLE PRACTICE: __get returns by reference
    // Also, overriding __get ONLY might not lead to an intuitive experience
    // As always, documenting non-standard behavior is paramount!
    public function &__get($name) {
        if ($name != 'cache') {
            // error handling
        }
        $type = get_class($this);
        if (!isset(self::$cache[$type])) {
            self::$cache[$type] = array();
        }
        return self::$cache[$type];
    }
}

然后,您将能够像

$b = new Base;
$b->cache['foo'] = 'bar';

看到它的实际效果

根本不使用静态 - 在大多数情况下,这不是一个正确的解决方案。创建一些存储对象(甚至可以是 ArrayObject)并将其传递给所有MyClass实例:

$sharedStorage = new ArrayObject();
$anotherStorage = new ArrayObject();
$instanceA = new MyClass($sharedStorage);
$instanceB = new MyClass($sharedStorage);
$instnceC = new MySubClass($anotherStorage);
它更简单,更容易

测试或维护,最重要的是,它不使用任何黑客,只使用常见的、众所周知的结构。

如果您担心它可能使用错误,例如:

$instanceA = new MyClass($sharedStroage);
$instanceB = new MyClass($anotherStroage);

创建一个工厂类,该工厂类将负责创建新对象。


顺便问一下,为什么你需要这样一个奇怪的要求 - 给定类的所有实例的公共存储,而不是该类的子类型?

这是我从这些答案中提炼出来的,我认为可能值得分享。太大了,无法发表评论,我不想对乔恩的答案进行如此实质性的编辑。

该解决方案有一个使用计数器,当最后一个类实例未设置时,它甚至可以释放缓存。它似乎从基础班开始工作,对孩子们没有任何麻烦。

class A {
  private static $aCacheAll = array();
  protected $aCache;
  function __construct(){
    $type = get_class($this);
    if(!isset(self::$aCacheAll[$type])){
      self::$aCacheAll[$type] = array(0,array());           
    }
    self::$aCacheAll[$type][0]++;
    $this->aCache =& self::$aCacheAll[$type][1];
  }
  function __destruct(){
    $type = get_class($this);
    if(!isset(self::$aCacheAll[$type])) return;
    self::$aCacheAll[$type][0]--;
    if(self::$aCacheAll[$type][0] <= 0){
       unset(self::$aCacheAll[$type]);
       // for testing
       print "Freed memory for $type cache'n";
    }
  }
  /**
   * Brain dead test functions
   */
  function set($x){
    $this->aCache[$x] = 1;
  }
  function get() {
    var_dump($this->aCache);
  }
}
class B extends A {}
/*
 * Test it
 */
$a1 = new A();
print "Empty on start: ";
$a1->get();
$a1->set('a');
print "Set a for A: ";
$a1->get();
$a2 = new A();
print "... and have it in '$a2, too: ";
$a2->get();
$b = new B();
print "But not in B: ";
$b->get();
$b->set('b');
print "Set b for B: ";
$b->get();
print "... is not in A: ";
$a2->get();
unset($a1);
print "Cache is retained, if '$a1 is freed, but vanishes when the final instance is unset: ";
unset($a2);
print "B cache still exists, until the program exits: ";

静态类变量?

http://php.net/manual/de/language.oop5.static.php

class Test {
  static protected $sharedInClassInstances = array();
  private $myOwnInstanceVariable = array();
  public function __construct() {}
}

Test的所有实例都应该能够访问与所有其他实例共享的Test::$sharedInClassInstances。而$this->myOwnInstanceVariable仅适用于单个对象。