这是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定义getter时,它返回自己的私有$foo
(= "world"
)。然而,如果我从类B中删除getter,并且类B从类A继承了完全相同的方法,它将返回父类A (= "hello"
)的私有$foo
属性。setter也是如此。
我期望继承的方法在任何时候都能访问实例化类的属性,而不引用它们祖先的私有属性。隐私是有原因的,不是吗?有副作用的隐私!如果我将prop可见性更改为public或protected,则会返回类B中预期的属性"world"answers"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)
如果我从A继承这两个方法,我得到"hello"
在两个计数。但是如果我在B中定义一个get()
,我分别得到"hello"answers"world"。你好,世界你好,宇宙在呼唤。我需要一些果汁。
编辑对于那些想知道我为什么在这里的人。简短的背景故事:我正在研究一个类层次结构,它在(数组)属性中增长得更深入,每个子类都是同一个向量的不那么抽象的版本。(就不举例子了。)我正在研究最聪明的方法来合并孩子的扩展属性与每个连续的父母的基础。
到目前为止,Private声明是防止子类覆盖父类属性的唯一方法,因为我可以通过使用父getter同时获得这两个类的属性。然而,这混淆了方法继承,如下所示。我想让这一切尽可能自动完成;最好使用单个clone_parent()
方法,该方法继承并在每个子构造函数中运行。我宁愿避免为每个父子扩展跳拼写单独的克隆器。(我在这里搜索和阅读了一堆,但仍未找到一个令人满意的解决方案。)
Edit2:其他方法悬而未决,在我的实际关注(如上所述),导致了这个实验。为了简单起见,我将省略子属性中的重叠声明,并调用extend_props
方法,该方法将继承自父属性的道具添加到上面。(唉,我希望每个扩展类的额外功能都显示在顶部,而不是隐藏在方法的下面!)
Private properties
are not accessible outside his own class
.
如果你要扩展一个类,它们也不能在外部访问。"看到父类的私有属性"的原因是您在父类中定义了getter
。这个getter可以访问private属性,因为他在同一个类中。这并不奇怪。
我建议你阅读更多关于private
, protected
和public
。