0

In my abstract class My_Class, I have a method My_Class::foo() that's called from within another method belonging to the class. For example:

abstract class My_Class {
    function foo() {
        // Stuff.
    }

    function bar() {
        $this->foo();
    }

    // More methods etc...
}

Now, I'm in the process of extending my abstract class. For example:

class My_Class_Extended extends My_Class {

}

As you'll know, both My_Class::foo() and My_Class::bar() are inherited by My_Class_Extended.

I never want My_Class::foo() to be called outside of My_Class or My_Class_Extended so I know not to make its visibility public. My problem is, I'm unsure whether to make its visibility protected or private.

My question

Considering how I'm calling My_Class::foo() in the above scenario, should it be made protected or private? I'm not sure if the call to My_Class::foo() is coming from the child or parent class.

Thanks in advance.

henrywright
  • 10,070
  • 23
  • 89
  • 150
  • 4
    As a general rule, always use protected unless you have a very specific reason why it needs to be private – Mark Baker Mar 10 '15 at 12:21
  • possible duplicate of [PHP: Public, Private, Protected](http://stackoverflow.com/questions/4361553/php-public-private-protected) – Mark Mar 10 '15 at 12:25
  • Are you asking about the difference between protected and private? Because both hide the function from the oustside world. The difference is that protected makes the function available to child classes. If you want that or not completely depends on your application architecture and your preferences. – Quasdunk Mar 10 '15 at 12:26
  • This is really a duplicate (See here: http://stackoverflow.com/questions/4361553/php-public-private-protected) but if you need something to be accessible by a child class it needs to be protected. – Mark Mar 10 '15 at 12:26
  • I've updated the question to show what I'm asking is slightly different to the question you linked to. – henrywright Mar 10 '15 at 12:43
  • `protected` properties and methods lead to violations of *Open-Closed Principle*, because they might be altered in descendant's class – Yang Mar 10 '15 at 12:54
  • @bad_boy you've now confused me. Should I not use `protected` then? – henrywright Mar 10 '15 at 13:05
  • @henry Protected variables and methods have their own use, but mostly people keep abusing them. Generally you should try writing classes which do *only one thing*, and mark their internal tools (methods and properties) as `private`. And a class itself should be marked like `final class Foo {}`. As for protected methods, you should always mark them as `final` too if you don't intend to override that method in descendant class. – Yang Mar 10 '15 at 13:13
  • Anyway, that's a whole topic, I can't answer about all best practices regarding this in one sentence. You'd better google yourself for something like this: *protected variables break encapsulation* or *inheritance breaks encapsulation* – Yang Mar 10 '15 at 13:15
  • @bad_boy - personally, I'd disagree with you.... private is frequently a contradiction of OCP precisely because it isn't Open, though that assumes the only way to open something is inheritance and doesn't take the possibilities of Composition into account – Mark Baker Mar 10 '15 at 13:42
  • @MarkBaker In simple words, *OCP implies that a developer should write classes in such way, that another developers can't modify*, but only use it and extend without altering "previous" state. Is that it what we're both referring to? My point here is that, when declaring a protected method, it should be marked as `final` so that it can't be overridden in child classes, thus adhering to OCP. As for protected properties, in PHP there's no way to make them `final`, so that they can't be easily altered in descendants. Again, it all comes to do inheritance and problems caused by it – Yang Mar 10 '15 at 13:59
  • Which is why I prefer composition over inheritance anyway.... but using private for everything can lead to tricky bugs when a class is extended and a new method/property with the same name is used – Mark Baker Mar 10 '15 at 14:40

1 Answers1

0

One-line: protected, because you want your child classes have access


The visibility modifiers work like this:

  • public: visible from everywhere.
    • $c = new My_Class_Extended(); $c->thisIsPublic();. This doesn't work with private or protected
  • protected: visible inside of the class and it's child classes
    • You can only call these functions inside of a function belonging to a class that derives from your parent class, or the parent class itself.
  • private: Only visible for the class it's defined in. You cannot call private functions in child classes, nor outside of the class.

The modifiers are ordered inclusively. So a protected is more restrictive than public, and private is more restrictive than protected.

You want protected, because you want to call them inside a child class, but not outside of it.


By the way: In your context, the abstract keyword only ensures that you cannot create an instance from My_Class.

Sbls
  • 495
  • 1
  • 4
  • 10
  • "You want protected, because you want to call them inside a child class, but not outside of it." But considering my scenario, is the call to `My_Class::foo()` actually coming from the child class? I'm not sure – henrywright Mar 10 '15 at 12:47
  • 1
    aaah! I misunderstood your question. In your example, it is *not* coming from the child class. So you *could* make it private. But that would prevent you from calling it inside `My_Class_Extended`. When you *also* want to be able to call it inside `My_Class_Extended` you need to make it protected. – Sbls Mar 10 '15 at 13:22
  • "In your example, it is _not_ coming from the child class." <-- that is the part I've been struggling to understand. I thought, because the method `bar()` is inherited by the child class, the call to `foo()` would then be taking place in the child. But you're saying that isn't the case? – henrywright Mar 10 '15 at 13:32
  • Sounds about right. You could regard both classes separately. `My_Class_Extended` doesn't override any of the parent functions. So `foo()` is called in `My_Class`. Imagine that `foo()` would be private. `My_Class_Extended` can't see `foo`, so it's the only possibility to be executed in `My_Class`. Maybe this example will give you more information: http://3v4l.org/Yg8n3 There is no function `foo()` in `My_Class_Extended`, hence the call to `foo()` *can't* be in the child class. – Sbls Mar 10 '15 at 15:13
  • Thanks for the example link. One thing: "There is no function foo() in My_Class_Extended" - so you're saying even though `foo()` is inherited by `My_Class_Extended`, it isn't considered to be a method that **belongs** to that class? – henrywright Mar 10 '15 at 15:20
  • Well, I didn't put this perfectly. `foo()` belongs to `My_Class_Extended`. But because we are talking about what function body get executed, it can't be the function body in `My_Class_Extended` because it doesn't exist. To be pedantic, non-static methods don't get called inside classes, but rather in objects. – Sbls Mar 10 '15 at 15:31