Object Overloading in PHP5

August 7th, 2007 : Austin Smith

One of my biggest complaints about PHP5 is that you can’t do genuine object overloading, you can only fake it using the __call() method and its brethren. The crappy part about __call() is that if you want to do anything complex, you end up reinventing the wheel in a big if, elseif… else block, or maybe a switch statement. It’s not well suited for real overloading, Java style. We’re better off just using func_get_args() at the top of a method and choosing different paths based on what we find in the function arguments. But that too can get overwhelming. I thought of a solution which I find interesting. I’m not saying it’s right, or even a good idea, but it comes as close to real overloading as anything, is quick enough to use, and demands strict variable typing.

A quick primer for those who need an OOP memory jog–overloading is where you can call a method (function, subroutine) by the same name but with different parameters (arguments). Think of a bowl–you can load it with Cereal and Milk, Stew, or Salad–you don’t want to allow just any Food object in there… what happens if another developer tries to pass your bowl object a hamburger? You have a mess, and your users end up eating their hamburger with a fork. Anyways, it looks like this in Java:

public void setLocation(double latitude, double longitude) { ... }
public void setLocation(String address) { ... }

In PHP, you’d have to do something like this:

public setLocationByCoords($lat, $long) { ... }
public setLocationByAddr($address) { ... }

Or like this:

public setLocation() {
$args = func_get_args();
if(count($args) == 2) { /* lat, long */ }
else { /* address */ }
}

Or this way (PHP’s sanctioned “overloading” method):

public function __call($name, $args) {
if($name == "getLocation") {
if(count($args) == 2) { /* lat, long */ }
else { /* address */ }
}
}

I don’t like any method that PHP offers, honestly, but the second one wins in my book (my book is about easy to read, concise code with as much abstraction as possible) because I don’t really want two different functions hanging around doing the same thing and __call() sucks unless you really badly want dynamic functions (sometimes I do). For you Ruby programmers, it’s the slightly lame equivalent of method_missing. What none of these three ways lets me do easily (actually, no way in PHP at all) is strict type enforcment. My lat and long function is going to be worthless without signed numbers with a lot of decimal places (doubles), and my address function would be pretty stupid with anything but a string. PHP doesn’t really give you a good way to do that, other than the impotent type hinting which only works for arrays and objects.

Now, I know that dynamic typing of variables is a major strength of PHP–it’s what got many of us into the language. But now it’s six years later and I’m still writing PHP, only now I’m doing it in big important web applications, which sometimes need stronger typing (file complaints below). So the solution I developed is as follows: call your function by whatever name you like, pass all its arguments to an Overloader class, and then check templates against the passed arguments. When a template matches, return the arguments in an object. Like this fully functional example (tried pasting it in here with horrible results), which will output the following:

3
Austin Smith
Bad Programmer!

Granted, that’s a really simple example, but I would see using this to split a function between only two or three possible argument types and primarily relying on it to punish those who disobey my typing orders. Of course, there’s a big drawback to this method–it doesn’t work with PHPDocumentor, although neither does __call() or the second of the PHP methods above. Truly, I long for the Java way. I’m hopeful for PHP6. Sigh.

The Overloader Class
A More Complex Example

Both of these are licensed under the MIT license. Again–and I repeat–I’m not claiming this to be an effective solution in the real world, all I’m saying is that it’s an interesting thought, and perhaps a useful way to improve the maintainability of a large code base. You can see that my way will take you a little bit more code–being a stickler for types almost always takes more code–but I suspect that it will come out in the wash (your implementation of your overloaded classes will be smaller) and take less time to develop and debug, especially as the size of the code base passes a certain point. I’ll let you know my mileage with this method.

Tags:

These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • ThisNext
  • Furl
  • Reddit
  • Slashdot
  • Technorati

Leave a Reply:

Subscribe without commenting