私有属性,顾名思义,就是私有的。这意味着它们只能从类中访问。正如其他人在 cmets 中提到的那样,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 ...
通过创建公共函数来访问和修改父类的属性,您可以让子类覆盖它们并执行自己的逻辑,而无需复制变量。然而,这也意味着B 的任何实例都可能改变A 中定义的值。为了缓解这种情况,您可以创建受保护的函数,允许 B 在内部访问和使用父类属性,但使用 B 的代码将无法执行相同操作。