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

时间:2012-04-20 10:05:12

标签: php oop static

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

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

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

4 个答案:

答案 0 :(得分: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';

<强> See it in action

答案 1 :(得分: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);

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


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

答案 2 :(得分:1)

这是我从这些答案中提炼出来的,我认为值得分享。评论太大了,我不想对Jon的答案进行如此大的编辑。

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

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: ";

答案 3 :(得分: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。虽然$this->myOwnInstanceVariable仅适用于单个对象。