35

The following code will have PHP unhappy that customMethod() is private. Why is this the case? Is visibility determined by where something is declared rather than defined?

If I wanted to make customMethod only visible to boilerplate code in the Template class and prevent it from being overriden, would I just alternatively make it protected and final?

Template.php:

abstract class Template() {
    abstract private function customMethod();

    public function commonMethod() {
        $this->customMethod();
    }
}

CustomA.php:

class CustomA extends Template {
    private function customMethod() {
       blah...
    }
}

Main.php

...
$object = new CustomA();
$object->commonMethod();
..
jontyc
  • 3,445
  • 6
  • 29
  • 36
  • 1
    I know this is a sample code, but please remove the brackets from `abstract class Template()` – nikksan Apr 27 '18 at 13:21

4 Answers4

60

Abstract methods cannot be private, because by definition they must be implemented by a derived class. If you don't want it to be public, it needs to be protected, which means that it can be seen by derived classes, but nobody else.

The PHP manual on abstract classes shows you examples of using protected in this way.

Tesserex
  • 17,166
  • 5
  • 66
  • 106
  • 11
    This differs from how C++ (and I think Java) behaves. C++ allows pure virtual functions (their equivalent to abstract functions) to be private. This is nice because it allows the derived class to specify and control WHAT to do, while enforcing that only the base class can choose WHEN to do it. Protected abstract functions cannot give you this same guarantee as the derived class can freely create a public function that calls the protected implementation and break the encapsulation. – Aaron Sep 27 '12 at 15:54
  • 4
    Work around: You can add the `final` keyword to the protected function in the abstract class definition (i.e. `final protected function my_function()` ). This will prevent the function from being overridden by child classes, though the child class can call the function for itself (something that cannot happen with a parent's private function). Whether or not this defeats the purpose of defining an abstract class is a philosophical discussion for another day. (Alternatively, you could define a new class that extends the abstract class and define the function privately there.) – Slicktrick Jan 13 '17 at 20:29
5

If you fear that customMethod will be called outside of the CustomA class you can make the CustomA class final.

abstract class Template{
    abstract protected function customMethod();

    public function commonMethod() {
        $this->customMethod();
    }
}

final class CustomA extends Template {
    protected function customMethod() {

    }
}
nikksan
  • 3,341
  • 3
  • 22
  • 27
  • Concise answer with supporting code. Since this thread has two questions and only one of them is addressed in the Accepted answer, I've upvoted this answer as well. – TonyG Nov 05 '21 at 16:46
3

Abstract methods are public or protected. This is a must.

MAChitgarha
  • 3,728
  • 2
  • 33
  • 40
fperet
  • 436
  • 8
  • 21
2

Nothing in PHP that is private in a child class is visible to a parent class. Nothing that is private in a parent class is visible to a child class.

Remember, visibility must flow between the child class up to the parent class when using abstract methods in PHP. Using the visibility private in this scenario with PHP would completely encapsulate CustomA::customMethod inside of CustomA. Your only options are public or protected visibility.

Since you cannot make an instance of the abstract class Template, privacy from client-code is maintained. If you use the final keyword to prevent future classes from extending CustomA, you have a solution. However, if you must extend CustomA, you will have to live with how PHP operates for the time being.

Anthony Rutledge
  • 6,980
  • 2
  • 39
  • 44
  • 1
    Nice thorough explanation. Since this thread has two questions and only one of them is addressed in the Accepted answer, I've upvoted this answer as well. This doesn't provide code like @nikksan but it explains carefully Why PHP behaves as it does. I was looking for a "contract" mechanism in PHP, to ensure derived classes implement Private functions in a consistent manner to improve maintainability. This can't be done AFAIK with an Interface. Using protected methods in a final child class seems to serve this purpose. This answer explains the process. – TonyG Nov 05 '21 at 16:52