PHP的属性和方法继承有什么奇怪的转折。请看下面的例子:PHP:为什么子类的继承方法访问父项的私有属性?
class A {
private $foo = 'hello';
function get() {
return $this->foo;
}
function set($val) {
$this->foo = $val;
}
}
class B extends A {
private $foo = 'world';
function get() { // try inheriting this
return $this->foo;
}
function set($val) { // try inheriting this
$this->foo = $val;
}
}
现在让我们来看看如何呼应了,如果我们继承或定义方法:
$b = new B();
/* If B defines getter: */
echo $b->get(); // 'world'
/* If B inherits getter: */
echo $b->get(); // 'hello'
// Enter Setter!
$b->set('cosmos');
/* If B defines setter & inherits getter: */
echo $b->get(); // 'hello'
/* If B inherits setter & defines getter: */
echo $b->get(); // 'world'
/* If B defines or inherits both: */
echo $b->get(); // 'cosmos'
所以:当B类定义,吸气,返回自己的私人$foo
(= "world"
)。但是,如果我从类B中删除了getter,而类B继承了类A的方法,它将返回父类A(= "hello"
)中的私有$foo
属性。同样与setters。
我期待继承的方法在任何时候都可以访问实例化类的属性,而不会引用它们的祖先的私有属性。他们是私人的原因,不是吗?私人与副作用!如果我将prop可见性更改为public或protected,则会返回B类的期望属性“world”和“cosmos”,无论方法是定义还是继承。
这里是对象转储每个以上的情况下:
var_dump($b);
/* If B defines getter (Prop get from B): */
["foo":"B":private] · string(5) "world"
["foo":"A":private] · string(5) "hello"
/* If B inherits getter: (Prop get from A) */
["foo":"B":private] · string(5) "world"
["foo":"A":private] · string(5) "hello"
// Enter Setter!
$b->set('cosmos');
/* If B defines setter & inherits getter
* Prop set to B & get from A */
["foo":"B":private] · string(6) "cosmos"
["foo":"A":private] · string(5) "hello"
/* If B defines getter & inherits setter
* :: Prop set to A & get from B */
["foo":"B":private] · string(5) "world"
["foo":"A":private] · string(6) "cosmos"
/* If B defines both:
* :: Prop set to B & get from B */
["foo":"B":private] · string(6) "cosmos"
["foo":"A":private] · string(5) "hello"
/* If B inherits both:
* :: Prop set to A & get from A: */
["foo":"B":private] · string(5) "world"
["foo":"A":private] · string(6) "cosmos"
能向我解释的人在发生了什么逻辑?继承的属性访问方法是否绑定到原始的方法定义父类的私有属性?我宁愿不要复制粘贴相同的方法到具有匹配名称的私有属性的每个子类中。
对不起,如果上面的插图继续恶心。为了我自己的理智,必须把它拼出来 - 这是出乎意料的行为,除非我错过了明显的东西。 (注:有构造函数或子类构造函数调用parent::__construct()
对此行为没有任何影响。)
地址:现在又进了一步。如果我声明getter受保护,并在B类中创建一个公共方法来获取变量。像这样:
class B {...
public function getpro_direct() {
return $this->foo;
}
public function getpro_getter() {
return $this->get();
}
...}
echo $b->getpro_direct(); // "world" (from B)
echo $b->getpro_getter(); // "hello" (from A)
如果我继承了一个替代这两种方法,我得到这两方面"hello"
。但是如果我在B中定义了一个get()
,我分别得到“hello”和“world”。宇宙你好,宇宙呼唤。我需要一些果汁。
编辑对于那些你想知道为什么我在这。简短的背景故事:我正在研究一个在(数组)属性中更深入生长的类层次结构,每个子类都是相同向量的较不抽象的版本。 (备用你的例子)我正在制定最聪明的方式来合并孩子的扩展属性和每个连续父母的基础。
到目前为止,私有声明是防止子类覆盖父类属性的唯一方法,因为我可以通过使用父类getter同时获得属性。但是,这样会弥补方法的继承性,如此处所示。我希望尽可能以自动方式完成此操作;最好用一个单一的clone_parent()
方法继承并在每个孩子的构造函数中运行。我宁愿避免为每个父 - 子扩展跳都拼写出单独的克隆。(我在这里搜索了一堆,但找到了一个令人满意的解决方案。)
编辑2:其他方法正在等待我的实际关注(如上所述)导致此实验。为了简单起见,我只是将重叠声明放在子项的属性中,并调用一个方法来添加从arent继承的道具。 (唉,我希望每个扩展类的额外功能都显示在顶端,而不是隐藏在方法内部的下方!)
无论您是否同意,这是预期的行为afaik,其原因是因为它是如何构建的。至于为什么它是这样建造的......呃......谁知道。但对我来说这确实有道理,但也许这只是PHP让我发疯。 –
你写过*好奇* - 这是否意味着私有属性在其他OO语言(例如C#或Java)中表现不同? –
@JonStirling如果这是它的构建方式,那么正确的...在我看来,如果你在子类中使用具有相同名称的私有属性,继承会变得复杂得多。我认为它的简短版本是**,我们不能继承访问私有属性**的方法。 –