我想实现一个缓存一些内部结果的类。这些结果对于类的所有实例都是相同的,即在所有实例之间共享此缓存可能是明智的。
然而,这些结果对于子类可能是不同的,即不应该与子类共享高速缓存。由于缓存对于所有子类也是一个好主意,因此该机制仍然是继承的。但每个子类必须使用不同的静态数组。
我可以想到各种黑客和复杂的模式来实现这个目标,但没有一个看起来真的很健全。有人知道PHP中的有效模式吗?
答案 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
仅适用于单个对象。