PHP从子上下文调用受保护的方法作为公共方法

3
我刚写了以下代码(期望它会失败),但我真的不明白为什么会出现这种行为:
<?php
abstract class Test1 {
    protected function methodTest1() {}
}

class Test2 extends Test1{
    public function methodTest2() {
        $test3 = new Test3();
        $test3->methodTest1();
    }
}

class Test3 extends Test1 {
}

$test2 = new Test2();
$test2->methodTest2();

期望结果:由于我调用了一个“受保护”的类成员,与公共成员一样,所以会发生致命错误。
实际结果:...正常工作。
我有什么遗漏吗?
我认为这与Test2扩展Test1有关,因此它可以访问它,但在这种情况下没有意义,因为我不是从Test2而是从Test3上下文中调用“test1()”。所以这意味着“Test3”是一个全新的实例,基本上不公开任何方法。从我的角度来看,这段代码使用了两个完全不同的对象实例。
即使IDE(PHPStorm)说它没问题。
有什么线索吗?
2个回答

3

这是正确的行为。可见性与类有关,不仅限于对象(类实例)。因此,下面的代码是有意义的:

class Foo {

    private $field;

    public function method(Foo $fooInstance) {
        //have access to everything from $fooInstance
        //cause I'm already in that class
        $fooInstance->field;
    }

}

对于受保护的成员,如果您在任何子类中使用并,则可以访问该成员。


我当然理解。我的担忧/问题是,从我的角度来看,创建一个新对象基本上意味着我正在使用一个新实例,因此所有标准规则都适用。然而,从http://php.net/manual/en/language.oop5.visibility.php的“其他对象的可见性”部分阅读似乎并非如此。这有点奇怪,你(至少部分地)同意吗? - Andrei Gabreanu
类型是相同的,但实例不同。我理解PHP OOP可见性的工作方式就像你所说的那样。至少从逻辑上讲,这没有意义(?)。类型明确表示该方法是受保护的,因此无法作为公共方法访问。在我的想法中,这意味着无论我在哪里创建一个新的Test3,我都无法访问任何方法(因为没有公共方法)。 - Andrei Gabreanu
1
嗯,不是从“任何地方”都可以访问吧?显然,如果您在定义Test3的块内编写代码,则不仅可以访问protected,还可以访问private。考虑一下私有可见性。诀窍是要想象从Test3内部工作的Test3对象“回家”,这样说。一旦从Test3块内部访问,它们就完全暴露了。但没关系,因为您仍然在Test3块中,所以无论您做什么,其他人都不会破坏封装,因为您已经知道了。不知道如何更好地解释它。 - Weltschmerz
Protected和Private很相似,只不过它包括了对子对象的这种访问自由。 - Weltschmerz
我同意关于受保护方法的观点。在这种情况下,封装被拉伸了,我不喜欢使用它们。这就是为什么我使用私有来说明可见性的原因。当涉及到私有访问时,封装被保留在一个块(文件)中,易于维护。 - Weltschmerz
显示剩余2条评论

1

受保护的变量可以在当前类和任何子类(即扩展该类的任何类)中访问。

考虑到您在Test2和Test3中都扩展了Test1,因此受保护的函数methodTest1()在这两种情况下都是可访问的。

如果您将methodTest1()从受保护更改为私有,则Test2和Test3将无法访问它。

Test3从Test2中被调用的事实是不相关的-两个类都扩展了Test1,因此两个类都可以访问methodTest1()。


我理解当然。我的担忧/问题是,从我的角度来看,创建一个新对象基本上意味着我正在使用一个新实例,因此所有标准规则都适用。[编辑]也从php.net关于OOP可见性找到了链接,似乎也说明了这一点。从我的角度来看有点奇怪,但没关系。感谢答案。 - Andrei Gabreanu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接