简体   繁体   English

PHP:为什么子类的继承方法访问父级的私有属性?

[英]PHP: Why do Inherited Methods of Child Class access Parent's Private Properties?

What a curious twist in PHP's property and method inheritance. PHP的属性和方法继承令人惊讶。 See the following example: 请参见以下示例:

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;
    }
}

Now let's see how that echoes out if we inherit or define methods: 现在让我们看看如果我们继承或定义方法,它会如何回显:

$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'

So: When class B defines the getter, it returns its own private $foo ( = "world" ). 因此:当类B定义getter时,它将返回其自己的私有$foo= "world" )。 However if I remove the getter from class B, and class B inherits the very same method from class A, it returns instead the private $foo property from the parent class A ( = "hello" ) instead. 但是,如果我从类B中删除了吸气剂,并且类B从类A继承了完全相同的方法,则它将从父类A( = "hello" )返回私有的$foo属性。 Likewise with setters. 与二传手一样。

I was expecting inherited methods to access the properties of the instantiated class at all times, with no reference to their ancestors' private properties. 我一直希望继承的方法可以随时访问实例化类的属性,而不引用其祖先的私有属性。 They are private for a reason, no? 他们之所以是私人的,不是吗? Private with side-effects! 私人有副作用! If I change the prop visibility to public or protected, the expected properties "world" and "cosmos" from class B are returned, whether methods are defined or inherited. 如果我将道具的可见性更改为public或protected,则无论是定义方法还是继承方法,都将返回类B的预期属性“ world”和“ cosmos”。


Here are object dumps for each of the above cases: 这是上述每种情况的对象转储:

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"

Can someone explain to me the logic in what's going on? 有人可以向我解释正在发生的事情的逻辑吗? Are inherited property-access methods bound to the private properties of the original method-defining parent class? 继承的属性访问方法是否绑定到原始方法定义父类的私有属性? I'd rather not copy-paste the same method into each child class that has private properties with a matching name. 我宁愿不将相同的方法复制粘贴到具有私有属性且名称匹配的每个子类中。

Excuse me if the illustrations above go on ad nauseam. 如果上面的插图经常出现,请原谅。 Had to spell this out for my own sanity huh -- unexpected behavior, unless I'm missing something obvious. 出于我自己的理智而不得不将其说明出来-意外的行为,除非我缺少明显的东西。 (NB Having constructors or invoking parent::__construct() in the child class constructor has no impact on this behavior.) (注意,在子类构造函数中具有构造函数或调用parent::__construct()对此行为没有影响。)


Add: Now one step further. 添加:现在又前进了一步。 If I declare the getters protected, and create a public method in class B for getting variables. 如果我声明吸气剂受到保护,并在类B中创建一个公共方法以获取变量。 Like so: 像这样:

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)

And if I inherit these two methods from A instead, I get "hello" on both counts. 而且,如果我改为从A继承这两种方法,则在这两种情况下我都会"hello" But if I define a get() in B, I get "hello" and "world" respectively. 但是,如果我在B中定义get() ,则分别获得“ hello”和“ world”。 Hello world hello, cosmos calling. 世界,你好,宇宙呼唤。 I need some juice. 我需要一些果汁。


Edit for those of you wondering why I'm at this. 编辑对于那些你想知道为什么我在这。 The short background story: I'm working on a class hierarchy that grows in more depth in (array) properties, with each child class being a less abstract version down the same vector. 简短的背景故事:我正在研究一个类层次结构,该类层次结构在(数组)属性中的作用越来越深,每个子类在同一向量上都是一个不太抽象的版本。 (Spare you the examples.) I'm working out the smartest way to merge the child's extended properties with each consecutive parent's basis. (为您节省示例。)我正在研究将子项的扩展属性与每个连续父级的基础合并的最明智的方法。

Private declaration was so far the only way to prevent the child class from overwriting the parent's properties, as I could have the properties of both simultaneously available via using the parent getter. 到目前为止,私有声明是防止子类覆盖父级属性的唯一方法,因为我可以使用父级getter同时获得这两个属性。 That however mucks up the method inheritance, as illustrated here. 但是,这会掩盖方法的继承,如此处所示。 I'd like to get this done as automagically as possible; 我想尽可能自动地做到这一点; preferably with a single clone_parent() method that's inherited and run in each child's constructor. 最好使用一个在每个孩子的构造函数中继承并运行的clone_parent()方法。 I'd rather avoid spelling out separate cloners for each parent-child extension hop. 我宁愿避免为每个父子扩展跃点拼出单独的克隆器。 (I've searched and read around a bunch here, yet to find a satisfactory solution.) (我在这里搜索并阅读了一堆书,但尚未找到令人满意的解决方案。)

Edit2: Other approaches pending, on my actual concern (as above) that led to this experiment. Edit2:关于我的实际关注(如上所述),导致该实验的其他方法有待解决。 To keep things simple, I'll just ditch the overlapping declaration in the child's properties and call an extend_props method that adds atop the props inherited from the arent. 为简单extend_props ,我将在孩子的属性中extend_props重叠的声明,并调用extend_props方法,该方法将在从arent继承的props之上添加。 (Alas I hoped to have each extending class's extras shown pretty up atop, instead of lurking down below inside a method!) (A,我希望每个扩展类的附加功能都显示在顶部,而不是潜伏在方法内部!)

Private properties are not accessible outside his own class . not accessible outside his own class Private properties

If you're extending a class, they aren't accessible outside too. 如果您要扩展课程,那么外面也无法访问它们。 The reason that you "see the private property of the parent" is that you've defined a getter in the parent. 您“看到父级的私有属性”的原因是您在父级中定义了一个getter This getter has access to the private property, because he is in the same class. 该获取者可以使用私有财产,因为他属于同一班级。 It's not strange. 这并不奇怪。

I suggest you to read more about private , protected and public . 我建议您阅读有关privateprotectedpublic更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM