samhuri.net


By Sami Samhuri

July 2006

Class method? Instance method? It doesn't matter to PHP

Update: This has been discussed for PHP6. A little late, but I guess better than never.

I made a mistake while I was coding, for shame! Anyway this particular mistake was that I invoked a class method on the wrong class. The funny part was that this method was an instance method in the class which I typed by mistake. In the error log I saw something like "Invalid use of $this in class function."

I knew for a fact I hadn't used $this in a class method, so it was kind of a confusing error. I went to the file in question and found out that it was calling an instance method as a class method. Now that is some crazy shit.

I would fully expect the PHP parser to give me an error like "No class method [foo] in class [blah]", rather than try and execute it as a class method. The syntax is completely different; you use :: to call a class method and -> to call an instance method. And you use the name of a class when you call a class method.

This code:


class Foo {
  public static function static_fun()
  {
    return "This is a class method!\n";
  }

  public function not_static()
  {
    return "This is an instance method!\n";
  }
}

echo '<pre>';
echo "From Foo:\n";
echo Foo::static_fun();
echo Foo::not_static();
echo "\n";

echo "From \$foo = new Foo():\n";
$foo = new Foo();
echo $foo->static_fun();
echo $foo->not_static();
echo '</pre>';

Produces:


From Foo:
This is a class method!
This is an instance method!

From $foo = new Foo():
This is a class method!
This is an instance method!

What the fuck?! http://www.php.net/manual/en/language.oop5.static.php is lying to everyone.

Late static binding

Update: This has been discussed and will be uh, sort of fixed, in PHP6. You'll be able to use static::mymethod() to get the real reference to self in class methods. Not optimal, but still a solution I guess.*

As colder on ##php (freenode) told me today, class methods in PHP don't have what they call late static binding. What's that? It means that this code:


class Foo
{
  public static function my_method()
  {
    echo "I'm a " . get_class() . "!\n";
  }
}

class Bar extends Foo
{}

Bar::my_method();

outputs "I'm a Foo!", instead of "I'm a Bar!". That's not fun.

Using __CLASS__ in place of get_class() makes zero difference. You end up with proxy methods in each subclass of Foo that pass in the real name of the calling class, which sucks.


class Bar extends Foo
{
  public static function my_method()
  {
    return parent::my_method( get_class() );
  }
}

I was told that they had a discussion about this on the internal PHP list, so at least they're thinking about this stuff. Too bad PHP5 doesn't have it. I guess I should just be glad I won't be maintaining this code.

The resident PHP coder said "just make your code simpler", which is what I was trying to do by removing duplication. Too bad that plan sort of backfired. I guess odd things like this are where PHP starts to show that OO was tacked on as an after-thought.

Ruby and Rails have spoiled me rotten

It's true. I'm sitting here coding in PHP using the Zend Framework and all I can think about is how much nicer Rails is, or how much easier it is to do [x] in Ruby. It's not that the Zend Framework is bad or anything, it's quite nice, but you just can't match Ruby's expressiveness in a language like PHP. Add the amazing convenience Rails builds on top of Ruby and that's a really hard combo to compete with.

I'd love to be using mixins instead of mucking around with abstract classes and interfaces, neither of which will just let you share a method between different classes. Writing proxy methods in these tiny in-between classes is annoying. (ie. inherit from Zendclass, then my real classes inherit from the middle-man class) I could* add things to Zend's classes, but then upgrades are a bitch. I miss Ruby. I could use something like whytheluckystiff's PHP mixins, which is a clever hack, but still a hack.

I keep looking at Rails code to see how things are done there, and I already coded a nearly complete prototype in Rails as a reference. I could have finished the thing in Rails by now, seriously. I'm still playing catch-up writing validations and model classes for all my objects, stuff I could've had for free using Rails, with an extra 10 mins to add validations and make sure they're all working nicely.

It's no wonder David H. Hansson wasn't able to write a framework he was happy with in PHP. After using Rails everything seems like a chore. I'm just coding solved problems over again in an inferior language.

But hey, I'm learning things and I still got to use Ruby even if the code won't be used later. I guess this experience will just make me appreciate the richness of Ruby and Rails even more.

Ubuntu: Linux for Linux users please

Ubuntu

is a fine Linux distro, which is why it's popular. I still use Gentoo on my servers but Ubuntu is fast to set up for a desktop. Linux for humans it certainly is, but dammit sometimes I want Linux like I'm used to.

It should ship with build-essentials (gcc & others) installed. It shouldn't ask me if I'm sure I want to restart at the GDM login screen. I have no session open and already clicked twice to choose Restart.

Other things aren't quite ready for humans yet. Network config needs some work. It's very slow to apply changes. Connecting to Windows printers should be easier (ie. let us browse to find them, or just search and present a list). Fonts aren't amazing yet, though Mac OS X has spoiled me as far as fonts are concerned.

Other than these things I think Ubuntu Dapper is a fine release. It installed on my work laptop without a problem and detected the volume keys and wireless network card flawlessly.

Working with the Zend Framework

At Seekport I'm currently working on an app to handle the config of their business-to-business search engine. It's web-based and I'm using PHP, since that's what they're re-doing the front-end in. Right now it's a big mess of Perl, the main developer (for the front-end) is gone, and they're having trouble managing it. I have read through it, and it's pretty dismal. They have config mixed with logic and duplicated code all over the place. There's an 1100 line sub in one of the perl modules. Agh!

Anyway, I've been looking at basically every damn PHP framework there is and most of them aren't that great (sorry to the devs, but they're not). It's not really necessary for my little project, but it helps in both writing and maintaining it. Many of them are unusable because they're still beta and have bugs, and I need to develop the app not debug a framework. Some of them are nice, but not really what I'm looking for, such as Qcodo, which otherwise look really cool.

CakePHP and Symfony seem to want to be Rails so badly, but fall short in many ways, code beauty being the most obvious one.

I could go on about them all, I looked at over a dozen and took at least 5 of them for a test-drive. The only one I really think has a chance to be the PHP framework is the Zend Framework. I really don't find it that amazing, but it feels right, whereas the others feel very thrown-together. In other words, it does a good job of not making it feel like PHP. ;-)

Nothing they're doing is revolutionary, and I question the inclusion of things like PDF handling when they don't even seem to have relationships figured out, but it provides a nice level of convenience above PHP without forcing you into their pattern of thinking. A lot of the other frameworks I tried seemed like one, big, unbreakable unit. With Zend I can really tell that nothing is coupled.

So I'll probably be writing some notes here about my experience with this framework. I also hope to throw Adobe's Spry into the mix. That little JS library is a lot of fun.