public / protected class属性是否不会覆盖父类的私有属性?

时间:2018-01-18 21:01:11

标签: php

在Parent类上声明私有属性,然后在Child类上将该属性重新声明为public或protected。

创建Child类的实例时,调用从Parent类继承的方法。使用Parent类的属性,而不是Child类的属性。

如果父类的属性的初始声明是公开的或受保护的,则不是这种情况。

有人可以向我解释为什么会这样吗?

<?php

class P {
    private $foo = 'bar';

    public function e()
    {
        echo get_class($this);
        echo "\n";
        echo $this->foo;
        echo "\n";
    }
}

class C extends P
{
    protected $foo = 'baz';
}

$parent = new P();
$child = new C();

$parent->e();
$child->e();

Output:
P
bar
C
bar

Expected Output:
P
bar
C
baz

1 个答案:

答案 0 :(得分:2)

私人财产,顾名思义,私有财产。这意味着他们只能在课堂上访问 。正如其他人在评论中提到的那样,this question提供了对PHP中变量范围的非常好的深入解释,所以无论如何都要查看它,这是一个有趣的读物。

然而,在您的具体情况中,您似乎担心在子类中重命名/重载变量。更具体地说,我们正在研究当父类和子类碰巧都具有相同名称的属性时发生的情况,并且父类具有返回该属性的函数。

class A {
    private $foo = 'bar';

    public function getFoo() {
        return $this->foo;
    }
}

class B extends A {
    protected $foo = 'something something';
}

$b = new B;

echo $b->getFoo();

在上面的示例中,输出为bar,实际上是预期的行为。由于函数getFoo未在子类中被覆盖,因此PHP在父类中执行该函数。当它到达时,$this引用A,因此打印$foo中定义的值A。值得注意的是,在此特定示例中,B::foo 的范围无关紧要。实际上,它可以完全省略,代码仍可以完美运行。

我们可以尝试不同的功能范围,看看会发生什么:

class A {
    private $foo = 'bar';

    public function getFoo() {
        return $this->foo;
    }

    private function getCapitalizedFoo() {
        return strtoupper($this->foo);
    }

    protected function getDoubleFoo() {
        return $this->foo . $this->foo;
    }
}

class B extends A {
    protected $foo = 'something something';

    public function getParentDoubleFoo() {
        return parent::getDoubleFoo();
    }
}

$b = new B;

echo $b->getFoo().PHP_EOL;      // Output: bar
echo $b->getParentDoubleFoo();  // Output: barbar
echo $b->getDoubleFoo();        // Output: Uncaught Error: Call to protected method ...
echo $b->getCapitalizedFoo();   // Output: Uncaught Error: Call to private method ...

现在,问题仍然存在:如何从父类访问私有成员?

如果您已阅读过该主题,您可能知道,除非完全必要,否则您的对象的属性应该是私有的,以便尽可能地封装其逻辑和数据。知道这一点,允许子类访问和修改其父类属性的最佳方法是为它们创建访问器和更改器。

class A {
    private $foo = 'foo';
    private $bar = 'bar';

    public function setFoo($foo) {
        $this->foo = $foo;
    }

    public function getFoo() {
        return $this->foo;
    }

    protected function setBar($bar) {
        $this->bar = $bar;
    }

    protected function getBar() {
        return $this->bar;
    }
}

class B extends A {
    public function __construct() {
        parent::setFoo('more foo');
        parent::setBar('more bar');
    }

    public function getCapitalizedFoo() {
        return strtoupper(parent::getFoo());
    }

    public function getCapitalizedBar() {
        return strtoupper(parent::getBar());
    }
}

$b = new B;

echo $b->getCapitalizedFoo();    // Output: MORE FOO
echo strtoupper($b->getFoo());   // Output: MORE FOO
echo $b->getCapitalizedBar();    // Output: MORE BAR
echo strtoupper($b->getBar());   // Output: Uncaught Error: Call to protected method ...

通过创建公共函数来访问和修改父类&#39;您允许子类覆盖它们并执行自己的逻辑而不必复制变量的属性。但是,这也意味着B的任何实例都可能会更改A中定义的值。为了缓解这种情况,您可以创建允许B在内部访问和使用父类属性的受保护函数,但使用B的代码将无法执行相同操作。