2

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

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

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

4

4 回答 4

4

一个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';

看到它在行动

于 2012-04-20T10:08:37.360 回答
1

根本不要使用静态 - 在大多数情况下,这不是一个正确的解决方案。创建一些存储对象(甚至可以是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);

创建一个负责创建新对象的工厂类。


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

于 2012-04-20T11:01:00.357 回答
1

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

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

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: ";
于 2012-04-20T19:19:43.877 回答
0

静态类变量?

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

class Test {
  static protected $sharedInClassInstances = array();
  private $myOwnInstanceVariable = array();

  public function __construct() {}
}

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

于 2012-04-20T10:06:46.923 回答