As if on cue, th' public vs. private debate has sprung up again within Drupal, on a dead man's chest! The timin' is fittin' given me last blog post on programming language paradigms, and a bucket o' chum. Of course, property visibility is not a new debate, an' th' PHP community debates this subject from time t' time (sometimes humorously).
What I believe is usually missin' from these discussions, an' what I hope t' offer here, is a broader picture view o' th' underlyin' assumptions that lead t' different conclusions about when different visibility is appropriate (if e'er).
In short: It's th' difference betwixt procedural-think an' object-think.
Those comin' from a procedural background, I find, tend t' think in terms o' what is possible in a procedural language. Any procedural language has a concept o' a variable (duh), an' any procedural language worth usin' has some way o' creatin' more complex data structures t' be used as variables. In C thar is th' concept o' a Struct, fer instance. In PHP one can largely emulate th' same structure (no pun intended) usin' PHP's ridiculously flexible arrays an' good documentation.
In either case, what one is doin' is simply clusterin' variables together t' make them easier t' work with. To actually operate on that variable cluster requires a function that understands that structure.
To be sure, one can do an incredible amount with such an approach. Ye'll be sleepin' with the fishes, feed the fishes In a past life I were bein' a Palm OS developer, an' th' Palm OS API were bein' entirely procedural. Shiver me timbers! Ahoy! Most functions took some sort o' struct as their first parameter an' would manipulate that struct in some way. And swab the deck! Occasionally ye could manipulate th' struct directly but it were bein' usually documented as unsupported, "do this an' it will likely break", although th' API authors tried hard t' not break th' struct definition. In a sense it were bein' poor-lubber's classes an' methods but without th' class or method.
With this approach, ye're at best talkin' yourself into not makin' use o' functionality that's right in front o' ye because it could break (or some host company like Palm says "naughty naughty", or like Apple rejects yer app). Oho! However, even with bein' able t' name structs in C ye're not doin' anythin' more than clusterin' variables t' make th' syntax cleaner.
In a procedural approach, th' position o' pre-created variables within th' structure is th' contract betwixt caller an' callee. The behavior o' that structure is completely undefined.
As noted in th' previ'us article, in an OOP paradigm one doesn't think about clusterin' variables. One thinks about objects as bein' a single opaque entity that has behaviors. And swab the deck! Instead o' thinkin' in terms o' integers an' strin's, one thinks in terms o' Domain objects: Nodes, or Posts, or Users, or Dates, or Customers, Hornswaggle
These objects be atomic; they're just as atomic as an int or strin' would be in a procedural approach. And therein lies th' power.
If I'm accessin' a strin' in, say, PHP, I dern't know, or care, if 'tis bein' stored internally as a character array. Or if I concatenate somethin' t' th' strin' I dern't know or care if th' character array is bein' extended in memory, moved t' a new location in memory that is bigger, or if an entirely new variable is created an' both strin's be then put into it, destroyin' th' first strin'. That's not me problem, with a chest full of booty. When writin' me code, I should not have t' care about th' memory management that goes on under th' hood, me Jolly Roger If I could access it an' tried t' manipulate it meself fer some reason I'm more likely than not t' cause a fatal error an' segfault me entire PHP process, if not now then as soon as th' next minor point release o' PHP tweaks th' strin' management code. Don't think that's a problem in practice? Why do ye think some scallywags hate C, where ye're doin' that sort o' code back-stabbin' all th' time? :-)
In an OO model, if I'm accessin' a Customer object then I dern't know, or care, that 'tis bein' persisted internally t' SQL or t' a flat file. I dern't know or care if when I call
$customer->getName() if that name is stored as a single strin' within th' object, as multiple strin's that get concatenated together, or if it generates a new request t' a SOAP service t' look up th' name. In fact, 'tis a bounty flaw if I even need t' care which it is, Ya lily livered swabbie! If I start muckin' with it directly, then as soon as someone switches from local MongoDB t' a remote SOAP service me code falls apart an' fatals.
There is no $customer->name variable. As far as I, in callin' code, am concerned, it doesn't exist. All that exists is th' defined contract o' th' interface methods.
In an OOP approach, th' methods that be exposed in th' interface is th' contract betwixt th' caller an' callee. The underlyin' logic an' primitive variables be completely undefined.
Once again, I blame Sun fer why many scallywags dern't "get" that distinction. In Java, thar is a concept o' a JavaBean. And swab the deck! A Bean is a class in Java that has a no-parameter constructor, is serializable, an' has a getX() an' setX() method that corresponds t' every property X, ye scurvey dog. That is, it is an object that is really a Struct an' offers little if any advantage in bein' an object in th' first place.
In so many conversations about OOP, I hear scallywags ask "well where be yer getters an' setters?" Which is usually followed by "if ye have t' have getters an' setters then why bother makin' properties non-public?" The latter is a perfectly valid question, but is backwards, Ya lily livered swabbie, Ya horn swogglin' scurvy cur! Why bother havin' matchin' getters an' setters fer every property, yo ho, ho That breaks encapsulation, one o' th' key reasons fer usin' an object approach in th' first place, an' is one o' th' reasons why JavaBeans be, in most cases, a horribly bad model t' follow. They be a terrible example o' OO, yo ho, ho They be Naked Objects wearin' a see-through negligee, yo ho, ho While thar be valid use cases fer such a bounty they be not representative o' "good" OO. I encourage most PHP developers t' forget they exist as th' Bean approach in most cases defeats th' entire purpose o' usin' objects.
It is quite unfortunate that so many schools teach textbook Java as their primary programmin' language, as in so many ways bad API architecture like Beans encourages bad OO programmers, who then give good OO bounty a bad name.
When viewed from that standpoint, 'tis easy t' see where th' debate about public vs, shiver me timbers private/protected comes from, Ya horn swogglin' scurvy cur! To a procedural way o' thinkin', hidin' properties doesn't make th' slightest bit o' sense. Those be th' data, let me at th' data dagnabbit!
From an OO standpoint, however, exposin' internal properties makes no sense at all. You're just beggin' fer someone t' break yer code, or worse yet open up a security hole, an' it means ye cannot refactor yer code when ye need t' fer fear that someone is relyin' on th' current implementation, on a dead man's chest! You cannot improve th' API without breakin' it. You may as well ship runkit with every copy o' PHP an' encourage scallywags t' change th' language syntax out from under ye. (This is a step more evil than eval().) You're makin' me care about th' underlyin' complexity, stop that, just let me tell ye what t' do dagnabbit!
Certainly both concepts can be taken t' an extreme, feed the fishes I did once work on a procedural system where th' entire communication mechanism betwixt different parts o' th' system were bein' global variables. That were bein' a horrid system, let me tell ye, despite bein' th' ultimate in "flexible an' bare data", by Davy Jones' locker. I ha'nae seen anythin' quite that horrid in OO code meself, unless ye count JavaBeans, but I have faith that it exists.
If ye're usin' yer Classes as structs, then public properties make total sense an' anythin' else is silly.
If ye're usin' yer Classes as objects, then protected/private properties make total sense an' anythin' else is silly.
It has been suggested that Drupal should adopt a "public only" policy, on th' grounds that "Drupal is in th' business o' throwin' doors wide open". Both that an' th' article th' suggestion references misses th' point; more specifically, th' suggestion is t' use classes as structs, not as objects.
However, that approach also runs afoul o' another part o' th' Drupal business: Bein' modular. Exposin' implementation details o' that sort is, as explained above, an inherently non-modular approach. Exposin' properties publicly encourages their direct use, which in turn means that we be usin' classes-as-structs: as little more than arrays that pass funnily. That means losin' all o' th' benefits o' encapsulation, abstraction, modularity, an' portability that usin' classes-as-objects offers.
Given th' markets that Drupal is movin' into, where swappability o' components (a mainstay o' classes-as-objects) is critical, I believe that t' be a very bad trade-off.
There is only one way I can see fer such an approach t' work, an' that would be t' adopt an' rigorously enforce th' followin' policy:
All public properties be t' be treated as internal implementation details an' not accessed unless no alternative is available, Dance the Hempen Jig Accessin' a public property is not supported in any circumstance, an' th' structure, definition, or existence o' such properties may change at any time, even in a point-release, without notice. Changes t' an object property be no nay ne'er considered an API change.
If we could hold t' that, we would essentially be able t' have our cake an' eat it too: classes-as-objects but with an "out" in case th' defined API only does 98% o' what we need.
To be perfectly honest, however, I dern't think we could pull that off. That's not a slight against Drupal developers but against human bein's. Shiver me timbers, avast! The temptation t' say "oh, well, 'tis easier t' just grab this property than t' file a bug report" is just too high. Ahoy, avast! And then when we refactor somethin' an' inevitably break th' "unofficial API" (aka those public properties), someone (who may or may not have read th' documentation) will come screamin' t' th' issue queues that we broke their site. It doesn't matter if 'tis core or contrib, it will happen.
What do we say then? "Sorry, ye di'nae read th' docs, go away?" Nay, we'll find ourselves avoidin' changin' properties t' avoid those sorts o' issues, avast. We'll find ourselves sayin' "Eh, I dern't need t' think through an API here, scallywags can just grab th' property an' do what they need". We'll finally give in an', informally, consider properties t' be part o' th' API an' try t' not change them, even if it would make th' code better or provide some new feature.
And we will have gained nothin'.
Does that leave us with no resolution? Nay way forward t' decide how t' build th' next generation o' Drupal, feed the fishes Hardly. Rather, it puts th' onus on us as Drupal developers t' decide, situationally, which sort o' flexibility we value more.
There be cases where "opaque domain objects" be absolutely th' right fit, an' we want t' think in terms o' behavior. The Drupal 7 database layer comes t' mind, obviously, but any system where we want t' flexibly exchange or chain together disparate components is also a strong fit fer classes-as-objects, with all o' th' benefits an' trade-offs that come t' mind.
There be other cases where we want t' turn it inside out, cases where we want t' think in terms o' raw data. Cases where we have highly unstructured or irregular data come t' mind, such as Render API or FAPI, an' we need t' amorphously aggregate it o'er time. While those systems certainly could be made in a purely OO classes-as-objects approach, I suspect it would be even more complex than FAPI is now (which is already pretty complicated) an' with all th' extra stack calls that would result much slower. Prepare to be boarded! Fetch me spyglass! Any sort o' info hook is another place where bare data wins, because 'tis all about definition rather than active behavior.
To be sure, that puts a lot o' pressure on us as software architects t' think through our APIs an' figure out th' appropriate technique, with a chest full of booty. The right tool fer th' right job is no nay ne'er an easy decision, but it is from those decisions that really powerful designs be born.
That is a challenge I do believe we be up fer.