Php 静态变量被初始化两次
我一直认为Php 静态变量被初始化两次,php,static,Php,Static,我一直认为static变量只初始化了一次,并将其值保留到脚本结束。然而,我在代码中遇到了一个bug,通过增加静态变量中的计数器来创建divID属性 下面是该bug的复制品: class Node { var $child = array(); public function test () { static $var = 0; $var++; echo $var,"\n"; foreach ( $this->
static
变量只初始化了一次,并将其值保留到脚本结束。然而,我在代码中遇到了一个bug,通过增加静态变量中的计数器来创建div
ID属性
下面是该bug的复制品:
class Node {
var $child = array();
public function test () {
static $var = 0;
$var++;
echo $var,"\n";
foreach ( $this->child as $c )
$c->test();
}
public function add_child ( $c ) {
$this->child[] = $c;
}
}
class Tree extends Node {
public function __construct() {
parent::add_child( new Node() );
parent::add_child( new Node() );
}
}
$tree = new Tree();
$tree->test();
上面有3个对test()
的调用,预期的输出应该是
1 2 3
但是,变量static$var
被初始化两次,产生以下输出:
1 1 2
有人能解释为什么会发生这种情况吗?看起来静态变量
$var
被树::测试()
和子节点::测试()
调用。我不确定最好的解决办法。但是我做的是使树::add_child()
添加class树的子对象
而不是class节点
class Node {
var $child = array();
public function test () {
static $var = 0;
$var++;
echo $var,"\n";
foreach ( $this->child as $c )
$c->test();
}
public function add_child ( $c ) {
$this->child[] = $c;
}
}
class Tree extends Node {
public static function createInitial() {
$tree = new Tree();
$tree->addChild();
$tree->addChild();
return $tree;
}
public function addChild() {
parent::add_child( new Tree() );
}
}
$tree = Tree::createInitial();
$tree->test();
这是一些令人讨厌的代码。当你遇到这样的问题时,最好退后一步,考虑另一种方法。否则,当您在6个月后回来添加新功能时,您将希望对键盘进行翻滚 在黑暗中拍摄,看起来(lsb)在这里工作。实例化的$tree对象创建了两个节点对象,每个节点对象都有一个test()方法,每个节点对象都绑定了一个
静态$var
$var每次调用的值
$tree->test() $tree->child[0]->test() $tree->child[1]->test()
1 1 2
请注意,$tree->child[1]->test()
调用输出一个2,这是因为静态$var
变量将自身绑定到$tree
对象,该对象在您进行初始$tree->test()调用时已递增
我在原始代码中添加了一些输出,以演示这一点:
class Node {
public $id;
var $child = array();
public function test () {
static $var = 0;
$var++;
var_dump(sprintf('Id: %d | Var: %d', $this->id, $var));
foreach ( $this->child as $key => $c ) {
var_dump(sprintf('Container Object Id: %d | Child Id: %d | Var: %d', $this->id, $c->id, $var));
$c->test();
}
}
public function add_child ( $c ) {
$this->child[] = $c;
}
}
class Tree extends Node {
public function __construct() {
$node1 = new Node;
$node1->id = 1;
$node2 = new Node;
$node2->id = 2;
parent::add_child( $node1 );
parent::add_child( $node2 );
}
}
$tree = new Tree;
$tree->test();
// Output
// Conclusion: $var bound itself to $tree during runtime
string 'Id: 0 | Var: 1' (length=14)
string 'Container Object Id: 0 | Child Id: 1 | Var: 1' (length=45)
string 'Id: 1 | Var: 1' (length=14)
string 'Container Object Id: 0 | Child Id: 2 | Var: 1' (length=45)
string 'Id: 2 | Var: 2' (length=14)
为什么不使用静态类成员,也许这样可以解决您的问题。这是一个有趣的问题,但是在类中使用静态函数变量看起来很奇怪<代码>类节点{public static$counter=0;/*…*/}
@feeela我同意,但我倾向于仅在多个方法中使用该变量时使用类成员。它使阅读和调试变得更容易,特别是在大班情况下。又是什么原因呢???这不是一个合适的问题吗?@Waldermort请看我的answer@Waldermort由于您正在扩展该类,因此即使在多个类中也可以有效地使用该变量。它不像那样有一个静态树::var属性和一个静态节点::var属性
。在哪里可以看到这两个类定义的静态属性?操作代码工作正常。好吧@voodoo417,我说错了,没有静态的Tree::var
或Node::var
属性,而是Tree::test()
和Node::test()
都是用OP的代码调用的。这是导致静态变量被启动两次的原因。请参阅手册中关于在函数(在本例中为-in-methods)中定义静态变量@voodoo417,我明确地说,我不确定这是否是最好的解决方案……但我试图解释问题并直接解决它,而不修改OP的逻辑。我仍然对我的答案感到满意,因为它直接解释并避免了OP提出的问题。你没有修改逻辑吗?您添加了新方法并更改了树中的几乎所有代码。您还不了解在这两种情况下静态是如何工作的(方法中的静态属性和局部静态变量)。我建议您也阅读文档。祝你好运从未想过LSB,但它是有意义的。刚刚在PHP4上进行了测试,但结果相同。我只能猜测编译器被调用了两次,每个类方法调用一次。直到PHP5.3.0才引入“static”关键字,你确定它是php4吗?php4也不支持公共的、受保护的、私有的可见性属性,所以如果您真的使用php4,您应该会遇到语法错误。我使用它是因为我没有在本地安装它。所以,这可能不是一个准确的测试。我将稍后安装它并进行真正的测试。