php 5.3中的后期静态绑定

时间:2012-06-17 14:53:29

标签: php 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?

2 个答案:

答案 0 :(得分:4)

我现在记得为什么后期静态绑定很有用。不幸的是,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()的公共getter,所以如果从test()类型的对象或对象调用A并不重要类型B,继承自A,因为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。

答案 1 :(得分:2)

foo本身并未复制到B(它是继承的但是不可见;请参阅下面的Gordon评论)。 B继承A->foo,调用A->test。要进行演示,请查看echo __CLASS__testfoo发生的情况(并删除导致错误的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!

这是继承的基本原则之一,因为它与information hiding / encapsulation有关。这允许你做这样的事情:

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;它只能通过$_list中定义的公共函数间接地对ListOfThings起作用。

查看PHP文档中的Visibility页面,了解有关此类内容的更多详细信息。