Access control and inheritance

[TOC]

This article verifies the conclusions obtained from the analysis

  • In-class calls are not restricted by access control constraints. Inter-class calls are restricted by access control constraints.
  • Only members modified by public can be accessed outside the class. That is, the instantiated object can only directly access the members modified by public. (Note: When the magic method __get () is declared in the class, the instantiated object accesses undefined or private members of the class is indirect access.)
  • The subclass and the parent class define a method with the same name at the same time.

    • The method with the same name in the parent class is modified by private, and the method with the same name in the subclass and the method with the same name in the parent class do not constitute an overriding relationship. And ① if there are other public methods in the parent class that call this method of the same name ② the child class does not override the public method that calls this method of the same name, then the instantiated object of the subclass accesses this public method, and the public method is called with the same name of the parent class method. (Reference to other articles: The $this in the function inherited from the parent class still points to the parent object in PHP? )
    • The method with the same name in the parent class is modified by public or protected, and the method with the same name in the subclass and the method with the same name in the parent class form an overriding relationship, but the access modifier of the method with the same name in the subclass is scope of the access modifier of the method of the same name of the 161454f3892645 161454f3892646, otherwise a fatal error will be reported. The general code editor will also prompt.
  • $this is a pseudo variable that represents a reference to the calling object. When a method is called inside the class definition, $this can be used.
  • __CLASS__ magic constant, which represents the current class. The function is the same as get_class(). To get the class name of the calling object's class, you can use the get_called_class() function, or get_class($this).

Access control

When a member (attribute or class constant or method) in a class is not modified by any access modifier, it is modified by pubic by default.
Access control modifierScope of actionWhether to participate in inheritance
publicInside the current class, inside the subclass, outside the current class, outside the subclassYES
protectedInside the current class, inside the subclassYES
privateCan only be accessed inside the current classNO
Note:
Only member methods participating in inheritance (modified by public or protected) can override (overriding). Because private modified private methods are invisible to subclasses, that is, it can almost be considered that private methods do not participate in inheritance. In addition, the (overload) overload in php is not in the true sense, like the concept described in other languages (such as java). PHP overload .

Sample code

The following code is written in a file named base.php, running environment PHP 8.

<?php
class Super
{
    public $name; //姓名
    public $gender; //性别
    protected $birth; //出生日期
    private $telephone; //手机号码

    // 构造方法
    public function __construct($name, $gender, $birth, $telephone)
    {
        $this->name = $name;
        $this->gender = $gender;
        $this->birth = $birth;
        $this->telephone = $telephone;
    }

    // 私有方法
    private function printHello() {
        echo __CLASS__ . ' hello' . PHP_EOL;
    }

    // 声明一个公有方法,调用上面的私有方法 printHello
    public function printTest() {
        $this->printHello();
    }
}

class child extends Super
{
    // 声明一个公有的与父类中私有方法 printHello 同名的方法 printHello,看是否构成对的父类中的同名方法的重写
    private function printHello() {
        echo "阿凡提de小毛驴";
    }
}

$init = ['绘梨衣', '女', '2003-08-12', '158xxxx0812'];
$super = new Super(...$init);
$child = new child(...$init);
echo $super->printTest();
echo $child->printTest();

Run the above code, the result output:

[Running] php "base.php"
Super hello
Super hello

[Done] exited with code=0 in 0.086 seconds

Key Analysis

Simplify the above code, focus on analyzing the public or protected methods of the subclass inheriting the parent class, calling the private method of the parent class, and then declaring the private method of the same name in the subclass, $this refers to the question.

The first case: the subclass directly inherits the parent class, and the subclass does not implement any methods.
<?php

class Super
{
    // 私有方法 printHello
    private function printHello() {
        echo get_called_class() . ' hello' . PHP_EOL;
    }

    // 声明一个公有方法,调用上面的私有方法 printHello
    public function printTest() {
        var_dump(get_class($this));
        var_dump(get_class_methods($this));
        $this->printHello();
    }
}

class child extends Super
{ 
    
}

$super = new Super();
echo $super->printTest();
echo '------------------------------------'.PHP_EOL;
$child = new child();
echo $child->printTest();

The output result is as follows. From the output result, we know that the subclass inherits all the methods of the parent class, including the private method printHello() of Super. Obviously this does not meet our expectations, because in other strongly typed object-oriented languages, private modified methods are described as non-inheritable. Here we can first think that this is due to the underlying implementation of php. We will not consider it first, and almost think that in php, private methods cannot be inherited. Students who have questions about this can refer to this article first, PHP kernel exploration: inheritance, polymorphism and abstract classes .

Based on this consideration, I think there is only one public method printTest() in the subclass. Outside the class, the instantiated object $child of Child will call printTest() because there is no accessible printHello() method in Child. , A Fatal Error is issued. However, it was inconsistent with what I expected. In the case of $child->printTest(), $this->printHello() inside printTest() accesses the private method printHello() of the parent class, and at this time $this is a reference to the $child object.

This can't help but make people wonder, how can the reference $this of the instantiated object of the subclass access the private method of the parent class? This unscientific.

string(5) "Super"
array(2) {
  [0] =>
  string(10) "printHello"
  [1] =>
  string(9) "printTest"
}
Super hello
------------------------------------
string(5) "child"
array(2) {
  [0] =>
  string(10) "printHello"
  [1] =>
  string(9) "printTest"
}
child hello
The second case: the subclass declares a printHello() method with the same name as the private method of the parent class

Note: This method does not constitute an overriding relationship with printHello() in the parent class.

<?php

class Super
{
    // 私有方法 printHello
    private function printHello() {
        echo get_called_class() . ' hello' . PHP_EOL;
    }

    // 声明一个公有方法,调用上面的私有方法 printHello
    public function printTest() {
        var_dump(get_class($this));
        var_dump(get_class_methods($this));
        $this->printHello();
    }
}

class child extends Super
{ 
    public function printHello() {
        echo "阿凡提de小毛驴";
    }
}

$super = new Super();
echo $super->printTest();
echo '------------------------------------'.PHP_EOL;
$child = new child();
echo $child->printTest();

The result is output as follows. From the results, $ child-> when printTest (), in this case $ child $ this is a reference object, printTest () inside $ this-> printHello () method to access private remains parent class printHello () instead of printHello() declared in the subclass. This is even more confusing.

string(5) "Super"
array(2) {
  [0] =>
  string(10) "printHello"
  [1] =>
  string(9) "printTest"
}
Super hello
------------------------------------
string(5) "child"
array(2) {
  [0] =>
  string(10) "printHello"
  [1] =>
  string(9) "printTest"
}
child hello
The third case: the child class overrides the parent class's public method printTest(), but the function body remains unchanged.
<?php

class Super
{
    // 私有方法 printHello
    private function printHello() {
        echo get_called_class() . ' hello' . PHP_EOL;
    }

    // 声明一个公有方法,调用上面的私有方法 printHello
    public function printTest() {
        var_dump(get_class($this));
        var_dump(get_class_methods($this));
        $this->printHello();
    }
}

class child extends Super
{ 
    public function printTest() {
        $this->printHello();
    }
}

The result is output as follows. The result at this time is in line with expectations, and $child->printTest() is a fatal error. Because there is no accessible printHello() method in Child. But even so, compared to the first case, new questions have emerged? The implementation of the overridden printTest() in the subclass is the same as the inherited printTest(). Why the first code does not report an error, but the current code reports an error because of the inherited printTest() and the overridden printTest() Is the location stored in the memory different?

string(5) "Super"
array(2) {
  [0] =>
  string(10) "printHello"
  [1] =>
  string(9) "printTest"
}
Super hello
------------------------------------
Fatal error: Uncaught Error: Call to private method Super::printHello() from context 'child' on line 26
Error: Call to private method Super::printHello() from context 'child'
The fourth case: the subclass declares a printHello() method with the same name as the parent class's private method, and the subclass overrides the parent class's public method printTest(), but the function body remains unchanged.
<?php

class Super
{
    // 私有方法 printHello
    private function printHello() {
        echo get_called_class() . ' hello' . PHP_EOL;
    }

    // 声明一个公有方法,调用上面的私有方法 printHello
    public function printTest() {
        var_dump(get_class($this));
        var_dump(get_class_methods($this));
        $this->printHello();
    }
}

class child extends Super
{ 
    public function printHello() {
        echo "阿凡提de小毛驴";
    }

    // 声明一个公有方法,调用上面的私有方法 printHello
    public function printTest() {
        $this->printHello();
    }
}

$super = new Super();
echo $super->printTest();
echo '------------------------------------'.PHP_EOL;
$child = new child();
echo $child->printTest();

The output at this time is as follows. I think this situation is the least doubtful and in line with expectations.

string(5) "Super"
array(2) {
  [0] =>
  string(10) "printHello"
  [1] =>
  string(9) "printTest"
}
Super hello
------------------------------------
阿凡提de小毛驴

This question has been answered in the Q&A initiated by me on this website

PHP, $this causes problems during inheritance?

Reference article:
A problem related to php inheritance
PHP static binding and dynamic binding
The difference between static binding and dynamic binding
of php object-oriented dynamic binding and static binding


kinra
19 声望0 粉丝