PHP bug of the day

I came across an annoying little bug in PHP this afternoon. Nothing I can't work around, but it's another example of the general suckiness of object-oriented programming in PHP.

Here's the situation. I've been slowly refactoring LnBlog over the last few months. I'm trying to make the design more object-oriented, easier to maintian, and just generally less messy and ad hoc. I'm adding in unit tests with SimpleTest and, at least today, I was actually working with a copy of Martin Fowler's Refactoring open in front of me.

The particular problem that popped up was with a class called Path that managers the building and converting of filesystem paths. Two of its methods are get() and getPath(). Both simply join a list of path components into a single path string. The difference is that get() is an instance method and works on instance variables. The getPath() method, on the other hand, is a static method where you just pass in the path components as parameters. Since these two methods do essentially the same thing, I thought that it would make sense to combine them.

In a language like C#, I would simply do this by overloading the get() method and having an instance get() with no parameters and a static get() with a parameter list. However, there is no overloading in PHP. The typical method is simply to fake it with optional parameters. Ugly, but it works.

Well, today I thought I'd be clever. I reasoned that, when a method statically, there is no instance of the class and hence the $this variable isn't set. So I tried something like the following: function get() { if (isset($this)) { return $this->implodePath($this->sep, $this->path); } else { $args = func_get_args(); return Path::implodePath(DIRECTORY_SEPARATOR, $args); } } The problem with this is that it only sorta, kinda works. More specifically, it only works when you don't call it statically inside another class method.

If you're familiar with bug 30355, this shouldn't come as a surprise. Turns out this behavior is actually for backward compatibility with various badly broken code. I can only hope that this is a bug that got grandfathered in rather than something that was originally done by design.

At any rate, the workaround was quite simple. I should have done it the first time - just replace that isset($this) with func_num_args() == 0. problem solved.

You can reply to this entry by leaving a comment below. This entry accepts Pingbacks from other blogs. You can follow comments on this entry by subscribing to the RSS feed.

Add your comments #

A comment body is required. No HTML code allowed. URLs starting with http:// or ftp:// will be automatically converted to hyperlinks.