For many years, I contemplated my privates with curiosity and confusion. We all know when to make our properties and methods public, but what about the private parts? Just how private should they be? Should our private parts be protected? After many years, I have finally come to a conclusion. In this post, let’s take a deep, introspective look at my private parts together.
A quick recap
In PHP, we are blessed to have 3 options for visibility: public, protected, and private. Public properties and methods can be accessed anywhere. There is generally little debate on when something should be public: if the outside world needs it, then it must be public for them to access it. If the outside world does not need it, then it should either be private or protected. Let’s quickly remind ourselves what the difference is.
Protected properties and methods are a little more lenient than private ones. Protected entities can be accessed by the class containing them AND any children or ancestors of that class. By contrast, private entries can strictly only be accessed by the class that contains them. PHP will not expose its private parts to the family. For example, take the following classes:
<?php
class mainClass
{
public function goMain(): void
{
echo $this->protected();
echo $this->private();
}
protected function protected(): string
{
return 'hello';
}
private function private(): string
{
return 'goodbye';
}
}
class childClass extends mainClass
{
public function goChild(): void
{
echo $this->protected();
echo $this->private();
}
}
Now let’s run them:
$main = new mainClass();
$main->goMain();
// outputs hellogoodbye
$child = new childClass();
$child->goMain();
// outputs hellogoodbye
$child = new childClass();
$child->goChild();
// outputs hello
// then Fatal error: Uncaught Error: Call to private method mainClass::private() from scope childClass
I hope I’m not belaboring the point, but only the mainClass can call the private method, while either class can call the protected one.
The dilemma
As mentioned earlier, it’s pretty clear when a property/method should be public. But protected vs. private is a lot less obvious. If related classes need to access the entities, then clearly they need to be protected. The question arises when no related classes currently need to access these entities.
According to my random number generator, 95% of classes will never be extended anyway. This means that the vast majority of non-public entities don’t explicitly need to be shared or hidden. So what should our default be? Protected or private? Should we start off as restrictive as possible and loosen up as needed? Or should we start with an eye on the future, assuming that any related class may need these entities and has a reasonable claim to access them?
Using privates
If it doesn’t specifically need to be protected, then make it private. Inheritance doesn’t need to be encouraged. It should be avoided by default and be reluctantly used when it makes sense. Protected entities shared between classes breaks encapsulation; one of the core tenants of good object oriented programming. Every time you choose to make something protected, you’re leaking to the outside world. Even if the leak is at least constrained to the family.
If you need to refactor something that’s private, you can just search for its usage within the class you’re in and adjust it as needed. When something is protected, you have to first check if your class is extending another class and then scan your whole project to see if any child classes extend the current one. If something does extend your class, then you also have to check if any classes extend THOSE classes as well! Even something as small as adding a return type to a method can break your program. So, you need to interrupt what you’re doing and check for any usages.
More likely, you don’t bother to check for child classes and instead just break your program occasionally. With private entities, we avoid this extra effort and danger.
As mentioned before, 95% of classes are probably never extended. Using protected entities then becomes misleading. You’re effectively saying “this property should only be accessible by me or my family members”. Which family members? “Oh, you know, nobody”. By contrast, private properties can freely be adjusted as needed. No need to search around the code base; even if the class does has family members, they won’t be perturbed by your changes.
If you follow this convention, then the reverse becomes true as well. When you see something that’s protected, you can assume that it IS referenced by related classes and therefore you absolutely should check around the code base to see if any other changes are needed.
If you make something private and it then later turns out to be needed by related classes, simply promote it to protected at that time. This already happens with private entities that end up being needed publicly anyway. Apply the same logic you would for public entities.
If you don’t already need it, You Ain’t Gonna Need It.
Conclusion
Don’t expose your private parts to the entire family. Follow my advice and use your privates as frequently as possible!