如果我的代码使用static
变量进行缓存,请执行以下操作:
class BossParty
{
// ...
public function getTemplate()
{
static $template;
if ($template == null)
{
$template = BossTemplate::get($this->templateID);
}
return $template;
}
// ...
}
$template
的不同实例会BossParty
持续存在吗?我已经尝试过检查php.net,但我能找到的只是关于静态类变量的信息。
答案 0 :(得分:7)
是的,静态变量将在类的实例中保持不变。
示例:
<?php
class Test {
public function __construct() {
static $foo;
if ($foo) {
echo 'found';
} else {
$foo = 'foobar';
}
}
}
$test1 = new Test();
$test2 = new Test();
// output "found"
请注意,对于后代类也是如此。如果我们有一个扩展Child
的课程Test
,则调用parent::__construct
(无论是显式还是隐式)都将使用相同的$foo
值。
答案 1 :(得分:2)
@ lonesomeday,这似乎是正确的。但是,特别是与您关于继承的后续注释有关,函数内部静态变量范围的行为似乎更复杂。我在所有的例子中都使用PHP 5.3.16。
摘要:用于对实例函数中的变量进行范围调整时static
关键字的行为似乎因继承和函数调用堆栈中的位置而异。
以下是一些例子。
首先,这与您的初始示例类似:在类的__construct()
方法中实例化静态变量,创建该类的两个实例,并查看该变量的行为。
<?php
// Example 1
class A {
public function __construct() {
static $i = 0;
$i++;
$this->i = $i;
}
}
$o1 = new A();
$o2 = new A();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>
到目前为止,没有惊喜。该变量被实例化一次(为0),然后随每个单独的实例递增。
如果将类A
扩展为B
,并实例化其中一个(使其他所有内容保持不变),则会出现相同的行为:
<?php
// Example 2
class A {
public function __construct() {
static $i = 0;
$i++;
$this->i = $i;
}
}
class B extends A {}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>
再次,没有惊喜。让我们回到第一个例子并稍微调整一下。首先,我们将静态变量实例化/增量调用移动到成员方法。请注意,我已删除此类B
:
<?php
// Example 3
class A {
public function __construct() {
$this->setI();
}
public function setI() {
static $i = 0;
$i++;
$this->i = $i;
}
}
$o1 = new A();
$o2 = new A();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>
仍然是相同的输出。
但,将A
扩展为B
,并保留相同的结构:
<?php
// Example 4
class A {
public function __construct() {
$this->setI();
}
public function setI() {
static $i = 0;
$i++;
$this->i = $i;
}
}
class B extends A {}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 1"
?>
请注意输出:在所有其他情况下,$o2->i
变为2,除此之外。
所以看来,如果我们将A
和扩展为静态实例化到实例方法,我们现在似乎已经为$i
变量引入了一个新范围,而在所有其他情况下,实例共享了该静态变量的范围。
更令人困惑的,请考虑这个例子;它与前一个相同,但是在这种情况下,类B
获得了自己的setI()
实现,它只是屈服于它的父类的实现:
<?php
// Example 5
class A {
public function __construct() {
$this->setI();
}
public function setI() {
static $i = 0;
$i++;
$this->i = $i;
}
}
class B extends A {
public function setI() {
parent::setI();
}
}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>
正如您所看到的,$o2->i
现在又回到了2,这就是我们几乎无处不在(示例#4除外)
对我而言,这似乎非常违反直觉。我希望 不同的实例获得该变量的自己的范围,或所有实例(包括扩展类的实例)共享相同的范围。
我无法判断这是PHP中的错误,还是预期的行为。 The PHP docs on static variable scope说:
静态变量仅存在于本地函数作用域中,但在程序执行离开此作用域时它不会丢失其值。
他们没有详细说明如何在对象实例的上下文中定义“函数范围”,因此我不确定示例#4中的边缘情况是否是预期的。
答案 2 :(得分:1)
是的,它也会在文档中记录,但它位于Variables Scope部分而不是Static Keyword部分,这可能是您找不到它的原因。