我想实现一个类,它缓存一些内部结果。这些结果对于类的所有实例都是相同的,即在所有实例之间共享此缓存可能是明智的。
然而,子类的这些结果可能不同,即缓存不应与子类共享。由于缓存对于所有子类也是一个好主意,因此该机制仍应被继承。但是每个子类都必须使用不同的静态数组。
我可以想到各种技巧和复杂的模式来实现这个目标,但没有一个看起来真的很正常。有人知道 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
与所有其他实例共享的。While$this->myOwnInstanceVariable
仅适用于单个对象。