Search code examples
phpinheritanceoverridingprivate

Is a private parent method "overridden" if child has an implementation of it?


There are several questions about weird behaviour when a child has an implementation of a private parent method like in the following example:

class A {
    private function toOverridePrivate() {
        echo "private toOverridePrivate A\n";
    }

    public function callInA() {
        $this->toOverridePrivate();
        echo "\n";
    }
}

class B extends A {
    private function toOverridePrivate() {
        echo "private toOverridePrivate B\n";
    }  

    public function callInB() {
        $this->toOverridePrivate();
        echo "\n";
    }      
}

$a = new A;
$b = new B;

$a->callInA(); // private toOverridePrivate A

$b->callInA(); // private toOverridePrivate A
$b->callInB(); // private toOverridePrivate B

When calling $b->callPrintsInA(), As implementation of toOverridePrivate is called, because B::toOverridePrivate is not accessible from A.

In summary it can be said, that the method must be accessible from the scope it is called, therefore the following fails:

class A {
    public function callInA() {
        $this->toOverridePrivate();
        echo "\n";
    }
}

class B extends A {
    private function toOverridePrivate() {
        echo "private toOverridePrivate B\n";
    }     
}

$b = new B;

$b->callInA(); // ERROR: Call to private method B::toOverridePrivate() from context 'A'

In the last example toOverridePrivate is not accessible in the scope of A, despite the fact that $this is in fact an object of type B.


But one aspect which varies between answers is, if having another implementation of a private parent method in a child class in overriding. In the most popular question I could find "Strange behavior when overriding private methods" the accepted answer says it is overriding...

Now if you override the private method, its new scope will not be A, it will be B

...while the second most voted answer states that...

A private method is not overridable

... because it is unkown outside of its class scope.


The last statement is questionable, because declaring a private method final makes overriding it not possible with the exact message that it can not be overridden:

class A { 
    final private function someMethod() { } 
}

class B extends A { 
    // Fatal error: Cannot override final method A::someMethod()
    private function someMethod() { } 
}

So...

Does a child class override a private parent method, if it has an implementation of that method? If this isn't overriding, what vocabulary would you use to describe it?


Solution

  • The child class simply has no knowledge of any private methods from parent class. Any such method in the scope of child class is undefined. It can't be overridden if it is not defined in the first place.

    If the method is public it is visible to everyone and any code can call it. When the method is protected in is only known to the class itself and any of its descendants. When a method is private it is only known in the scope of this class. To any other class this method is simply undefined.
    You can define another method with the same name in the child class, but it is not overriding anything. You could still call it overriding, but it would not make much sense. Overriding means that if you do not redefine the method in the child class it will call the definition from parent class. With private methods it is not possible because they are not accessible from the child class.

    Consider this example:

    class A {
        private function toOverridePrivate() {
            echo "private toOverridePrivate A\n";
        } 
    }
    
    class B extends A {
        public function toOverridePrivate() {
            parent::toOverridePrivate();
        }   
    }
    
    $o = new B;
    
    $o->toOverridePrivate();
    

    Fatal error: Uncaught Error: Call to private method A::toOverridePrivate() from context 'B'

    Whether the class B defines method toOverridePrivate or not, it makes no difference, because the method toOverridePrivate from A is always inaccessible.