$ this对继承方法的行为

bfa*_*tto 2 php oop inheritance this

我一直以为我理解OOP是如何工作的(我多年来一直在使用它),但有时我意识到一些概念对我来说仍然不太清楚.

我刚刚遇到了关于PHP中方法可见性的问题.该接受的答案解释说,私有方法不能在PHP中的子类覆盖.好的,这是有道理的.但是,这个例子让我想到了PHP中的内部继承机制,以及$this对继承方法的行为方式.

考虑一下这段代码(PHP手册中的例子,也包含在上面提到的问题中):

class Bar 
{
    public function test() {
        $this->testPrivate();
        $this->testPublic();
    }

    public function testPublic() {
        echo "Bar::testPublic\n";
    }

    private function testPrivate() {
        echo "Bar::testPrivate\n";
    }
}

class Foo extends Bar 
{
    public function testPublic() {
        echo "Foo::testPublic\n";
    }

    private function testPrivate() {
        echo "Foo::testPrivate\n";
    }
}

$myFoo = new foo();
$myFoo->test();

/* 
Output:

Bar::testPrivate
Foo::testPublic
*/
Run Code Online (Sandbox Code Playgroud)

现在考虑PHP手册中的这段摘录:

当从对象上下文中调用方法时,伪变量$ this可用.$ this是对调用对象的引用(通常是方法所属的对象,但如果从辅助对象的上下文中静态调用该方法,则可能是另一个对象).

解释说明" $this是对调用对象的引用",即$myFoo.所以我希望$myFoo->test()永远都会调用Foo::testPrivate,而且永远不会Bar::testPrivate(除非$myFoo是实例Bar).我测试$thisget_class,它总是返回Foo,甚至从内部Bar::testPrivateBar::test.但是,$this行为类似于调用Bar时的实例.Bar::test$this->testPrivate()

这真的令人困惑,我试图理解为什么它会这样运作!

我认为继承的方法(publicprotected)以某种方式从基类复制到子类.私有方法根​​本不会被复制.但是这个例子表明它不能像这样工作.它看起来像Foo保留内部实例的实例Bar,并在必要时委托方法调用它.

我想在这里学习一些东西,而我只会在事情对我有意义的时候学习.这个没有.写完这些之后,我想我可以用两个问题来总结它:

  1. 有人可以简要解释一下继承如何在PHP 内部工作?或者至少指向一篇关于它的文章或文档?

  2. $this此处的行为或讨论是否也存在于其他OO语言中,还是特定于PHP?

Bor*_*lid 5

PHP中的继承与大多数面向对象语言中的继承相同.

如果使用"虚拟"方法,则该方法不会直接绑定到调用方.相反,每个类都包含一个小的查找表,其中说"此方法名称绑定到该实现".那么,当你说$this->testPublic(),实际发生的是PHP:

  • 获取当前类的虚拟表
  • testPublic在该表中查找虚拟表条目
  • 调用查找指向的方法

由于Foo覆盖testPublic,其虚拟表包含一个用于testPublic指向的条目Foo::testPublic.

现在,使用私有方法,行为是不同的.因为,正如您正确阅读的那样,私有方法无法被覆盖,因此调用私有方法永远不会导致虚拟表查找.也就是说,私有方法不能是虚方法,必须始终在使用它们的类中定义.

因此,效果是名称在声明时被绑定:所有Foo方法将Foo::testPrivate在他们说出时调用$this->testPrivate,并且所有Bar方法都将调用Bar::testPrivate.

总而言之,说"继承的方法被复制到孩子"是不正确的.实际发生的是,子进程的方法名称查找表以其父类的条目填充,然后添加自己的函数并替换任何被覆盖的条目.当您调用时$this->something,将查询此查找表以获取当前对象的类.所以,如果$this是一个实例Foo,并且Foo覆盖testPublic,你得到Foo::testPublic.如果$this是一个实例Bar,你会得到Bar::testPublic.