静态变量被初始化两次

时间:2014-01-27 23:06:35

标签: php static

我一直认为static变量只被初始化一次并保留它们的值直到脚本结束。但是我在我的代码中遇到了一个错误,其中通过增加静态变量中的计数器来创建div ID属性。

这是错误的复制品:

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

有人可以解释为什么会这样吗?

2 个答案:

答案 0 :(得分:2)

看起来$var和孩子Tree::test()正在调用静态变量Node::test()。不确定解决这个问题的最佳方法。但我所做的是让Tree::add_child()添加类Tree的子对象而不是类Node

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();

答案 1 :(得分:1)

这是一些讨厌的代码。当您遇到这样的问题时,最好退后一步,考虑另一种方式。否则,当您在6个月内回来添加新功能时,您需要使用键盘面板。

在黑暗中拍摄,看起来像Late Static Binding(lsb)在这里工作。您实例化的$ tree对象创建了两个节点对象,每个节点对象都有一个test()方法,每个方法都绑定了static $var

每次通话

$ var值

$tree->test()    $tree->child[0]->test()    $tree->child[1]->test()
1                1                          2

请注意,$tree->child[1]->test()调用输出2,这是因为static $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)