PSR-0: Great Idea, Bastardised Execution

If there’s one thing PHP needs, it’s a bit more convention. Node and Ruby can both attribute a large portion of their success to their respective package managers. Unfortunately PHP has such a… diverse history that using different components between frameworks and projects often requires a cumbersome set of differing bootstraps and loaders. PSR-0 looked set to be at least a partial solution; a common naming convention such that files could be loaded in the same way, regardless of their original framework. And they royally screwed it up.

I know I’m a bit late to the party, but like all people I only started to moan when it started to affect me. My framework of choice, Kohana, added PSR-0 compliance to the 3.3 development branch. And broke how every existing user expected the framework to work.

Firstly a bit of background on what PSR-0 actually it. PHP Standards Recommendation 0 is a guideline for how classes, their files and autoloaders should work to ensure harmony between projects. Set up by a group called FIG (supposedly made up of the major framework players, but with little in the way of online presence) it’s become so much of a standard now that PHP itself is deciding whether to include it in the core SPL. At it’s most basic if you have the class foo_bar, the autoloader should look in foo/bar.php for the class definition. Simple. Underscores (and namespaces) become directories and the last part becomes the filename.

Except once again PHP’s history rears its ugly head. You see, in PHP Foo and foo and FOO all represent the same class. That’s right, functions and variables are case sensitive, but not class names. There are reasons for this, and it can actually be useful (especially when dynamically generating class names in routing libraries and drivers), but ultimately this is something that cannot change without risking breaking all existing projects. So what to do?

The logical choice is simple: normalize all class names when generating file paths, typically by lowercasing the class name first. So Foo_Bar, foo_BAR and FoO_bAr should all look in foo/bar.php. And this is exactly what Kohana and a dozen other frameworks did. But they didn’t write PSR-0, the big boys did; Zend, Symfony et al. And they decided to do things “the correct way” i.e. the way they’d been doing it for years.

So, what’s the problem you might ask? Just name your files the same way. Great! Until you start hitting the edge cases. Calling “new foo()” after calling “new Foo” would work, but swap the order of those two arguments and suddenly your code breaks. Or even better, develop on a local filesystem that’s case insensitive by default e.g. OS X/HFS+ and then deploy to a live server and watch everything crumble before your eyes.

The solution to this was so simple; a single call to strtolower(). Tools like Git make it ridiculously easy to rename files and preserve history. Instead, we now have to refactor code to ensure every call represents the same class. If we want “pretty URLs” with dynamically extracted controllers, we now need to start breaking naming conventions e.g. Controller_BlogPost would only match /BlogPost/view/123 so now you end up with classes such as Application_Controller_blogpost.

This is the first time I’ve felt motivated enough to write about something in the PHP community. I can take all the stick from other languages, I can get over the haphazard naming conventions, but this? Right when PHP was moving in the right direction they go and screw it all up. If PSR-0 gets included the SPL autoloader it’ll be game over. Thanks for reading.

5 Responses to PSR-0: Great Idea, Bastardised Execution

  1. Jahanzeb says:

    Thanks, this and another article really cleared things about PSR-0 for me. Just goes to show you should’nt ever stick to just one language! Can you tell me if Codeigniter moved to PSR-0? I’m not really sure.

    • Luke L says:

      CodeIgniter 2 doesn’t even use a standardised autoloader so no. I believe there’s been some discussion for future versions.

  2. If you are having problems deploying between case-insensitive and case-sensitive filesystems, you are doing something wrong. Just because PSR-0 does not specify how your classes should be named (it’s only about the namespace and class filesystem structure, PSR-1 expands upon it to do that) doesn’t mean you should not have a standard. Whether PSR-1 or your own version (camelCase, for instance), you should apply the same conversion before loading a class file.

    For example, if your standard is to name classes in camelCase and store them in camelCase.php, you should always try to convert the class name before trying to build the file path. new BlogPost should be lcfirst’d (at the most basic) to blogPost before you try to include it.

    And the idea that the URL /BlogPost/ would try to blindly load BlogPost.php is crazy. If you’re directly including files from what’s handed in as a URL segment without any logic in between you just need to stop what you’re doing, the name of the file being in a different case is absolutely the least of your problems.

    • Luke L says:

      I am not arguing for any specific class naming convention! In fact, I follow PSR-0 in that I use StudlyCaps with namespaces (or underscores for non-namespaced applications). Where I take issue is with the corresponding filenames. PSR-0 says the files should match, i.e. BlogPost would be stored in BlogPost.php. My argument is, lowercasing all filenames removes *any* potential autoloading issues. Factories do not have to worry about any case conversions or formats. It’s not a “preference”, it’s simple normalization logic.

      As to your final point, a lot of simpler MVC front-requests route URLs based on /// , this makes it very simple to get off the ground. I’d also like to point out (please don’t take this as a personal attack), that your own code on GitHub follows the lowercased filename pattern, with class names having a different name.

  3. Rico says:

    Take a look at PHPab. We use it instead of PSR-0 and only implement PSR-1 and 2.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>