php 5.3 中的后期静态绑定


Late static binding in php 5.3

请浏览下面给出的代码,它来自php手册

<?php
class A {
    private function foo() {
        echo "success!'n";
    }
    public function test() {
        $this->foo();
        static::foo();
    }
}
class B extends A {
   /* foo() will be copied to B, hence its scope will still be A and
    * the call be successful */
}
class C extends A {
    private function foo() {
        /* original method is replaced; the scope of the new one is C */
    }
}
$b = new B();
$b->test();
$c = new C();
$c->test();   //fails
?> 

谁能解释一下这里到底发生了什么?

为什么 foo() 会被复制到 B ?

我现在记得为什么后期静态绑定很有用。不幸的是,php.net 的例子解释得很差。请参阅此(修改后的)示例:

<?php
class A {
    private function foo() {
        echo __CLASS__;
    }
    public function test() {
        $this->foo();
        static::foo();
    }
}
class B extends A {
    public function foo()
    {
        echo __CLASS__;
    }
}
$b = new B();
$b->test();
?>

如果你运行上面的代码,你会注意到它有效,你会得到AB。为什么?

  • 它之所以有效,是因为test()foo()的公共获取者,所以无论你是从 A 类型的对象调用 test() ,还是从继承自AB 类型的对象调用 都没有关系,因为test()将始终可以访问定义它的类的私有成员。
  • 在第一种情况下,$this->foo();总是会调用A::foo()因为绑定是在本地完成的,在A的范围内,这有时是很不希望的。请参阅此评论: http://www.php.net/manual/en/language.oop5.late-static-bindings.php#83502
  • 在第二种情况下,static::foo();指示解释器确定$b的类型,并查看在哪个类中尝试找到foo()。在这种情况下,B::foo()被视为A::foo()的覆盖方法,因此,基本上,如果B::foo()存在,则调用它,否则,解释器将查找A::foo()
  • 尝试将B::foo()标记为私有并运行我提供的示例,看看会发生什么。我认为这个测试和我上面的咆哮将为您澄清问题;)

另外,我接受对上述观点的任何评论,因为我已经有一段时间没有使用PHP

foo本身

并没有被复制到B(它是继承的,但不可见;参见下面Gordon的评论)。B 继承 A->foo ,它调用 A->test 。若要演示,请查看从 testfoo 内部echo __CLASS__时会发生什么情况(并删除导致错误的static::foo()调用):

class A {
    private function foo() {
        echo __CLASS__."->foo'n";
        echo "success!'n";
    }
    public function test() {
        echo __CLASS__."->test'n";
        $this->foo();
    }
}

输出:

A->test
A->foo
success!
A->test
A->foo
success!

这是继承的基础之一,因为它与信息隐藏/封装有关。这允许您执行以下操作:

class ListOfThings {
    // internal structure (top secret!)
    private $_list = array();
    // add item to list
    public function add($item) {
        $this->_list[] = $item;
    }
    // return number of items in list
    public function count() {
        return count($this->_list);
    }
}
class ListOfStates extends ListOfThings {
    // do we have all 50 states?
    public function allStatesListed() {
        return $this->count() === 50;
    }
    // try to access internal structure of ListOfThings
    public function accessInternalStructure() {
        sort($this->_list);
    }
}
$states = new ListOfStates;
$states->add('ME');
$states->add('NH');
$states->add('VT');
$states->add('RI');
$states->add('CT');
var_dump($states->count());
var_dump($states->allStatesListed());
$states->accessInternalStructure();

输出:

int(5)
bool(false)
Warning: sort() expects parameter 1 to be array, null given...

如您所见,ListOfStates能够使用ListOfThings的所有公共功能,即使这些函数都依赖于私有变量$_list。也就是说,ListOfStates不能直接操纵$_list;它只能通过ListOfThings中定义的公共职能间接

地作用于$_list

查看 PHP 文档中的可见性页面以获取有关此类内容的更多详细信息。