20

我很难理解为什么我们会得到这段代码的输出:

<?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(); 
?>

所以 Foo 扩展了 Bar。$myfoo 是 Foo 类的对象。Foo 没有名为 test() 的方法,因此它从其父 Bar 扩展它。但是为什么 test() 的结果是

Bar::testPrivate 
Foo::testPublic

你能解释一下为什么第一个不是 Foo::testPrivate,当这个父母的方法在孩子中被覆盖时?

非常感谢您!

4

6 回答 6

12

可能testPrivate是因为顾名思义,它是一个私有方法,不会被类继承继承/覆盖。

在 php.net 手册页上,您可能从中获得了该代码,明确指出We can redeclare the public and protected method, but not private

所以,到底发生了什么:testPrivate如果只有子对象,子类不会重新声明方法,而是在“范围”中创建它自己的版本。正如test()在父类中定义的那样,它将访问 parents testPrivate

如果您要test在子类中重新声明该函数,它应该访问 childs? testPrivate()方法。

于 2012-10-24T07:07:42.180 回答
6

除了声明类之外,私有方法对任何东西都不可见。由于您testPrivate从父类调用,它唯一可以访问的方法是它自己的方法声明。因此你得到你看到的输出。但是,如果访问修饰符 be protected,那么您将获得您期望的输出,因为受保护的方法在整个继承链中都是可见的。

于 2012-10-24T07:07:41.010 回答
5

private成员不能被覆盖,只有公共和受保护的成员可以。这意味着,事实上,testPrivate没有被覆盖,所以Bar看不到它,仍然调用它自己的testPrivate

于 2012-10-24T07:07:00.730 回答
5

因为private意味着private。没有其他类,甚至子类都不知道Bar::testPrivate(),因此不能覆盖他们甚至不知道的东西。

Foo::testPrivate()只能在里面使用Foo。因为这private就是全部。

更多信息:覆盖私有方法时的奇怪行为

于 2012-10-24T07:07:43.247 回答
3

手册

声明为私有的成员只能由定义该成员的类访问。

当您的测试函数在基类 Bar 中运行时,它将访问自己类中的私有函数。

于 2012-10-24T07:06:41.460 回答
3

这不是特定于 PHP 的。继承规则要求可覆盖受保护的和公共的功能。私有函数有自己的作用域,对于泛化类是不可见的。

请在 Java 中找到以下相同的情况,相同的结果:

Bar::testPrivate

Foo::testPublic

除非您可能会收到警告

The method testPrivate() from the type Foo is never used locally    Foo.java    

因为Java是编译的。

public class Bar 
{
    public void test() {
        this.testPrivate();
        this.testPublic();
    }

    public void testPublic() {
        System.out.println("Bar::testPublic\n)");
    }

    private void testPrivate() {
        System.out.println( "Bar::testPrivate\n");
    }
}

public class Foo extends Bar {
    public void testPublic() {
        System.out.println("Foo::testPublic\n");
    }

    private void testPrivate() {
        System.out.println("Foo::testPrivate\n");
    }

    public static void main(String[] args) {
        Foo myFoo = new Foo();
        myFoo.test();
    }
}
于 2012-10-24T07:15:01.657 回答