我一直以为我理解OOP是如何工作的(我多年来一直在使用它),但有时我意识到一些概念对我来说仍然不太清楚。
我刚刚遇到this question关于PHP中方法可见性的问题。 accepted answer解释了PHP中的子类不能覆盖私有方法。好的,这是有道理的。但是,这个例子让我想到了PHP中的内部继承机制,以及$this
在继承方法上的行为方式。
考虑此代码(example from the PHP Manual,也包含在上述问题中):
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
*/
现在考虑这个excerpt from the PHP Manual:
从对象上下文中调用方法时,伪变量 $ this 可用。 $ this是对调用对象的引用(通常是方法所属的对象,但如果从辅助对象的上下文中静态调用该方法,则可能是另一个对象)。
说明中指出“$this
是对调用对象的引用”,即$myFoo
。所以我希望$myFoo->test()
总是会调用Foo::testPrivate
,而永远不会Bar::testPrivate
(除非$myFoo
是Bar
的实例)。我使用$this
对get_class
进行了测试,并始终返回Foo
,即使是在Bar::testPrivate
和Bar::test
内也是如此。但是,当$this
调用Bar
时,Bar::test
的行为类似于$this->testPrivate()
的实例。
这真的令人困惑,我正在努力理解为什么它的工作原理!
我认为继承的方法(public
或protected
)以某种方式从基类复制到子类。私有方法根本不会被复制。但是这个例子表明它不能像这样工作。看起来Foo
的实例保留了Bar
的内部实例,并在必要时委托方法调用。
我想在这里学习一些东西,而我只会在事情对我有意义的时候学习。这个没有。写完这些之后,我想我可以用两个问题来概括它:
有人可以简单解释一下继承如何在PHP内部内部工作吗?或者至少指向一篇关于它的文章或文档?
此处讨论的行为或$this
是否也存在于其他OO语言中,还是特定于PHP?
答案 0 :(得分:5)
PHP中的继承与大多数面向对象语言中的继承相同。
如果使用“虚拟”方法,则该方法不会直接绑定到调用方。相反,每个类都包含一个小的查找表,其中说“此方法名称绑定到该实现”。所以,当你说$this->testPublic()
时,实际发生的是PHP:
testPublic
的虚拟表条目由于Foo
会覆盖testPublic
,因此其虚拟表包含指向testPublic
的{{1}}条目。
现在,使用私有方法,行为是不同的。因为,正如您正确阅读的那样,私有方法无法被覆盖,调用私有方法永远不会导致虚拟表查找。也就是说,私有方法不能是虚方法,必须始终在使用它们的类中定义。
因此,效果是名称在声明时受到约束:所有Foo::testPublic
方法在他们说Foo
和所有Foo::testPrivate
方法时会调用$this->testPrivate
将致电Bar
。
总而言之,说“将继承的方法复制到子级”是不正确的。实际发生的是,子进程的方法名称查找表以其父类的条目填充,然后添加自己的函数并替换任何被覆盖的条目。当您致电Bar::testPrivate
时,此查询表会参考获取当前对象的类。因此,如果$this->something
是$this
的实例,并且Foo
覆盖Foo
,则会获得testPublic
。如果Foo::testPublic
是$this
的实例,您将获得Bar
。
答案 1 :(得分:2)
嗯,private
方法和属性就是私有的。对于所有意图和目的,您可以将它们视为“内部”,意味着它们所定义的类的内部。这意味着它们永远不会被继承,并且永远不会被覆盖。
因此,当$this
与private
方法或属性结合使用时,它始终是与$this
<的引用相同的类中的方法或属性 / em>的。发生这种情况是因为父类中调用的$this
无法访问另一个类中的private
方法或属性(因为它们是私有的),甚至来自子类。
希望这有帮助。