Pragmatism over Theory: Protected vs Private

Fabien Potencier

March 29, 2011

I often favor pragmatism over theory; probably because programming is how I earn a living but also because I don't have any computer science degree and what I know I've learned from my experience.

In the recent months, there have been a lot of discussions in the PHP community about the usage of private over protected visibility for methods and properties in Open-Source libraries.

To summarize my point of view:

"private" is for purists and "protected" is for pragmatic developers.

Coming from Perl, I've been a strong advocate of never using private for anything (as far as I remember, there is not a single use of private in symfony1; and until recently, the usage of private was explicitly disallowed in Symfony2 -- it was even part of the Symfony2 coding standards!).

So, why Symfony2 changed its mind? Yep, I've just wrote Symfony2, not I. As Symfony2 is a community driven project and because we have such a large number of contributors, I'm not the only one who take decisions. And if some people have strong arguments, I'm willing to change things even if I'm not a big fan of them.

Anyway, a couple of weeks ago, we have started to switch most protected properties and methods to private. And guess what, just two weeks after the change, I already have two great stories and lessons to share with you.

Besides obvious mistakes we have fixed right away, all the requests we had for reverting back to protected lead to better solutions so far.

First, someone complained about not being able to customize the Routing component. Here is the conversation we had on Twitter (translated from French):

@InformatHic: The closing of the Symfony2 API is a real ordeal. (cc @fabpot)

@fabpot: @InformatHic we can reopen the API if necessary. But give me examples first.

@InformatHic: Finally I cleaned up my code and I must say that it is much cleaner now. (cc @fabpot)

Having a few well defined extension points force the developer to extend your library the right way instead of hacking your code.

And now, for the second example. The Symfony2 Console component is used by many PHP libraries outside the Symfony world, like Behat. For Behat, Konstantin used to override some methods that I've switched from protected to private. At first, he was annoyed. But after some discussion with Bulat, they came up with a much better solution: they actually decoupled the code and added a new and clean way to solve the problem at hand and as a result, they made the component more beautiful and more customizable.

Closing the API allows design flaws to be found more easily and gives you the opportunity to evolve your code by creating well defined extension points.

So, even if I still believe that using private is not a hard rule you should blindly follow, I can see some pragmatic advantages. And it's not like we cannot change our mind if needed. Changing a private method to protected is simple and won't break any code. But before doing that, you need to understand what the developer is trying to achieve and if you cannot find a better way to resolve his problem without opening the API too much.

By the way, public methods does not define the public API. Sometimes, you need to declare a method as public because you need to access it from another class in your library; but that does not mean that you want your users to actually call it directly. What do you do then? Symfony and Flow3 have decided to mark the "real" public API with the @api tag. All classes, methods, and properties tagged with @api are public in the sense that we guarantee their stability over time: their name, signature, and behavior won't change for any minor version of the library. That's a strong commitment; one that I like much better than any strict enforcement done on the language level.

Discussion

gravatar Riad Benguella  — March 29, 2011 11:11   #1
I totally agree about the choice of private / protected but shouldn't public methods define only the public API.

I mean, classes should only call other classes API, and to avoid calling methods which are not meant to be public, a better solution can always be found... am I wrong ?
gravatar beberlei  — March 29, 2011 11:14   #2
The problem with "public" in PHP is that there is no differentiation between namespace and global visibility, which makes stunts like @Api actually necessary if you want to guarantee backwards compability to users.
gravatar Florian Klein  — March 29, 2011 11:15   #3
I personally think the Console component example can be controversial:
this is possible if the library is still changing, like Symfony, but as soon as the library is stable, I don't see how you could refactor it to make it more extensible without breaking things.

So yes for private first and change them to protected if needed, but if it requires refactoring and breaking the library, is it good?

Finally, I think privates force you to potentially break things in the future.
gravatar desfrenes  — March 29, 2011 11:18   #4
"Sometimes, you need to declare a method as public because you need to access it from another class in your library;"

Would you mind giving us an example ?
gravatar Fabien Potencier  — March 29, 2011 11:20   #5
@florian: That's why you will want to use private early on; before the library becomes stable.

"Finally, I think privates force you to potentially break things in the future."

That's quite the contrary actually. You cannot break things with private methods. And if needed, you can still change them to protected.
gravatar beberlei  — March 29, 2011 12:17   #6
@florian klein: You can always move away from all private methods/variables to a more open approach without breaking BC. It just doesnt work the other way around.
gravatar umpirsky  — March 29, 2011 14:25   #7
If you want to protect method from overriding, better use final. Protected looks better to me, especially for libraries, because you give more flexibility to end users.

Again, it depends on concrete needs, but I prefer protected.
gravatar Ren  — March 29, 2011 14:52   #8
I believe too many private or protected methods is a code smell.

And if find an class having too many, then perhaps it's an indication that the class needs refactoring/splitting. This would also make methods more testable.
gravatar Andrey Esaulov  — March 29, 2011 19:41   #9
For us, day-to-day web hardworkers, Symfony end users the tighter closed API means stabilitiy. And that is a good thing.
Keep 'em methotds private, do not let me break anything! Just bwcause one sunny morning I decide to be a smart a** and extend native Symfony Core (Look, Fabien haven't thought of that,he-he!), does not mean I am allowed to do this!
Save me my own time, spent on debugging my own stupidity, and just keep those methongs shut ;)
gravatar Koc  — March 29, 2011 23:41   #10
Why there are public query/request/cookie properties in the Request class, without any getters?
gravatar Luke Morton  — March 30, 2011 01:40   #11
Firstly I'd like to say I've never used private since I assumed keeping methods as protected allows my code to be extensible. However I can see potential benefits as you have given examples for that can come about with private methods and properties.

I'm interested in knowing if you followed any particular methodology when it came to privatising protected methods? Did you simply replace every protected with private and fix all the errors and refactor methods as appropriate or perhaps you had a more focused plan of attack?
gravatar metagoto  — March 30, 2011 07:06   #12
@desfrenes
Cases where you would use the friend relationship in c++ or the "internal" access modifier in c#
gravatar Wil Moore  — March 30, 2011 10:51   #13
@Ren:

I sort of agree with you but I'd leave it at:
Many methods is a code smell.
gravatar gerard  — March 30, 2011 10:53   #14
"don't touch it, don't even look at it"

For anyone who that is lost on. "ours go to eleven"
gravatar Florent  — March 30, 2011 12:07   #15
Actually,

an improvement like the one requested here <http://bugs.php.net/bug.php?id=52297> would help, imho ;)
gravatar Dmitri  — March 30, 2011 16:08   #16
I never use private for anything - protected all the way. This is especially important for an open source projects where there is a great chance that someone will be extending your classes. Also it's harder to write test cases because you cannot extend private methods in your test.
gravatar OZ  — April 16, 2011 23:56   #17
What a strange idea with "@api tag"?
You can use interfaces to declare API, but not strange tags.

And fields should be declared 'protected' when class designed to be extended, and 'private' otherwise - all simple. Any other rules (like 'all fields must be private') looks non-logical as minimum.
gravatar Houtsnip  — April 18, 2011 13:39   #18
To play the devil's advocate: when people refactor their code, they often do end up with something better (after all, isn't that the purpose of refactoring?).

Is it possible that the code was improved not because closing the API forced people to refactor, but just because of the simple fact that they were forced to refactor at all? A lot of companies (including all those that I have worked for) don't really approve of refactoring - they would rather produce crap code, but make more money. So if there is some horrible code that works despite it's horribleness, we just leave it. We refactor when there is a real need.
gravatar Bart van Wissen  — April 29, 2011 09:37   #19
It's unfortunate that we have to make methods private only because we don't want people to override it.
Why doesn't PHP have 'final' methods like Java?
gravatar Bart Wissen  — April 29, 2011 09:41   #20
Duh, please delete my last comment. It does have final methods of course. I have even used them frequently.
Apparently I'm still sleeping.
gravatar Me Again  — May 05, 2011 14:15   #21
+1 for Ren

Private methods are usually a sign that those methods don't belong in the current class, but in a separate class that provides services for the current one.