Chad Perrin: SOB

22 March 2007

PHP + OOP = a mess

Filed under: Geek — ???? @ 03:15

Hello, apotheonistas!

Sterling here. Not only is this the first-ever guest post on SOB, it’s also my first guest post anywhere. I’ll do my best to give you something approaching the apotheonic while Chad’s away. Not that I could imitate apotheon. But hopefully you’ll at least find enough interesting content here to keep your mouse off the kill switch for a few minutes.

Chad gave me the inspiration for my first topic in an IM chat before he left, characterizing the object syntax in PHP as

… a kludge for people who started with the wrong language to support current growth, but don’t have the resources to rewrite the software in another language.

That “kludge” has at least two aspects: (1) the language syntax itself, and (2) customary usage.

Syntax

PHP’s OOP syntax is better than Perl’s, and not quite as good as Java’s. Like Perlobj, OOP was added to PHP as an afterthought — and it shows. That gives it one advantage over Java, though, in that you aren’t forced to use classes for every piece of code you write (Ruby provides a much better solution to that problem, by making classes ubiquitous yet unobtrusive).

But that’s where PHP’s superiority over Java ends, IMHO. Oh, it does inheritance and encapsulation OK (even interfaces — which Ruby again outdoes via mixins). When it comes to polymorphism, though, Polly skipped PHPtown. Partly this has to do with the generally loose typing in PHP, but even though you can invoke stronger typing using Type Hinting, you can’t redeclare a function for different types of a parameter. That leaves you deciding between (a) using is_a (case on type, ugly), (b) creating different member functions to handle different parameter types (moving the case on type into the client code), or (c) trying to build any differences in manipulating the objects into methods of the classes being passed (gets clunky real fast).

What passes for “overloading” in PHP seems to me the most bizarre feature of its OOP syntax. The magic methods (whenever you see something documented as “magic”, run)__get(), __set(), and __isset() essentially provide a mechanism for handling “properties” — i.e., a way to hide getter and setter methods under an ostensible variable reference. But they funnel all such access through a single channel, which forces you to (a) adopt a very uniform internal mechanism for access, or (b) do a case on name to decide how to handle each one. I don’t even want to think about using __call(). That’s just insane obfuscation along the lines of the COBOL ALTER statement, as far as I can tell.

Usage

Most of the object-oriented PHP that I’ve seen really isn’t OOP at all. Usually, they employ a class merely to prevent naming conflicts with variables and function names. That’s what namespaces are for, duh. Oh, wait, PHP doesn’t have namespaces. So, they create a singleton instance of a class, store its handle in a global variable, and reference member data and functions off that one global reference. The bailing wire and bubble gum version of namespaces, but it works.

But then, almost without fail, these PHP wizards find that requiring client code to access a global variable doesn’t sit well. So they wrap the singleton object within an API composed of straight-up functions. Which once again invades the global namespace and undoes half the benefit of using a class in the first place. Some good examples of this can be found in the WordPress core code — cache.php, for instance.

In short, when OOP gets added to PHP, you usually get POOHP.

All original content Copyright Chad Perrin: Distributed under the terms of the Open Works License