Visibility in PHP

It's often said that php5 has a much improved object model, in part because of the new visibility keywords: public, private and protected. But do these really do anything useful? I would argue that they are at best irrelevant and at worst positively harmful.

Consider for a moment an average house with average doors and windows. How often do visitors try to climb in through a window rather than ring the doorbell? It just doesn't happen. Although they could that doesn't mean they will. Setting bear traps beneath the windows is wasted effort.

Encapsulation is of course a fundamental, non-negotiable OOP principle. There must be a clear distinction between public interface and private methods. However, this is simply a labelling issue: it doesn't actually need to be enforced. The experience of coding in php4 ought to make this clear. Improper calling of non-public methods wasn't a frequent problem, or an occasional problem, or even an extremely rare problem. I don't remember ever having a problem at all. OOP worked very well in php4 despite the lack of visibility keywords. By convention, notionally-private methods were clearly labelled with underscores and nobody seemed to get confused. In php5 you can work in exactly the same way with no adverse consequences.

As always, testing helps to stay focussed on real requirements. In TDD one does the simplest thing to make a test pass and so the question is: what failing test might there be which could be made to pass by adding public, private or protected? There isn't one. Non-public methods are never called in tests and so visibility won't matter. If you stop and think about it, there is no reason to restrict access which can be related to a real, domain requirement. Rarely, you might have a need for reflection but again this is simply a question of labelling.

It's always surprisingly easy to allow imaginary requirements to creep into the code. At the least, they add their own dead weight to carry around. At worst, they can trigger a whole cascade of additional problems and complexity. In this case the php developers have a lot of extra work to do supporting the new visibility model and all of its ramifications. Also, legions of ordinary php programmers will end up learning that pointless verbosity is some kind of best practice in direct opposition to the ideals of simplicity, elegance and clarity which they should be absorbing. Private, public and protected add a lot of clutter which makes code harder to read but our keenest instinct should be a loathing for unnecessary complexity. Our job is to pare things down to their essentials, expressing complex logical processes as simply as possible.

Debugging becomes more awkward than it needs to be when everything is locked away out of sight. Very occasionally it's quite useful to be able to peek under the bonnet. I think that's allowed when you're not acting as a normal user: mechanics should be allowed to rummage around all they like.

I see that ReflectionProperty is to get a setAccessible() in 5.3. In a sense that's a long journey right back to where we started. That's what happens when a genuine requirement, labelling, is confused with an imaginary one, access restriction. It can be a very easy trap to fall into. There is always some apparently irresistible argument.

What would I like to see? Underscores seem to be a simpler solution for the labelling issue and simpler is always better (I continue to code this way in php5). If something really had to be added to the language a simple "+" and "-" for public and protected would have saved millions of poor coders from eyestrain and RSI's. Don't bother enforcing them and of course nothing at all for private: it's evil. Maybe also dump "function" while we're at it:

<?php    
    
class Foo {
    
__construct() {
        ...
    }
    +
publicMethod() {
        ...
    }
    -
internalMethod() {
        ...
    }
}
?>

Private is Evil

The idea that an object needs to be encapsulated against itself, with private variables or methods, is rather odd. An inheritance hierarchy is like a family and family members can ask anything of each other. There may be many classes but there is only ever one object. Objects, not classes, are the units of encapsulation.

If that paradigm doesn't seem to fit I think it's time to rethink the division of responsibilities. A perception that something is exposed and needs to be fenced off may be real enough but a new (aggregated) class is the way to deal with that. Private bits are a code smell indicating a bloated inheritance hierarchy which needs to be broken up.

In this way private is actually an enabler of bad design: a kind of sticking plaster which lets you patch up a sickly patient, slowly bleeding to death. Without it you'd be forced to find a proper cure. A feature widely touted as improving OOP in php may actually have the opposite effect.

Marking bits private to prevent them from being overridden is a pointless exercise in any case. It doesn't stop anyone overriding anything: it just makes it harder, requiring the programmer to rip out and redo a bigger pile of code. Don't expect to be thanked for that. You can never know in advance how users might want to extend your code. The algorithm which you were so keen to lock down might be the very thing which they need to change. Whatever arguments you might have, they are always trumped by the open-closed principle.

Private can also make code exponentially harder to understand. Imagine a big-boned hierarchy which has two or more classes with a private foo() method (I'm not sure if I really can imagine that but it is possible). Each foo() could be called at different times within the same instance depending on where in the hierarchy the call was made. That could be very difficult to follow and an extra gotcha to watch out for if you shuffle bits around in a refactoring.

SourceForge.net Logo