@ 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 中的错误,或者它是否是预期的行为。静态变量范围的 PHP 文档说:
静态变量只存在于局部函数作用域中,但当程序执行离开此作用域时,它不会丢失其值。
他们没有详细说明如何在对象实例的上下文中定义“函数范围”,所以我不确定示例 #4 中的边缘情况是否是预期的。