Migrating OOP Libraries and Frameworks to PHP 5.3

With PHP 5.3 coming up on the horizon, I'm of course looking forward to using namespaces. Let's be honest, who wants to write the following line?


$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');

when the more succinct:


$viewRenderer = HelperBroker::getStaticHelper('viewRenderer');

could be used? (Assuming you've executed 'use Zend::Controller::Action;' somewhere earlier...)

However, while namespaces will hopefully lead to more readable code, particularly code in libraries and frameworks, PHP developers will finally need to start thinking about sane standards for abstract classes and interfaces.

For instance, we've been doing things like the following in Zend Framework:

  • Zend_Controller_Request_Abstract
  • Zend_View_Interface

These conventions make it really easy to find Abstract classes and Interfaces using find or grep, and also are predictable and easy to understand. However, they won't play well with namespaces. Why? Consider the following:


namespace Zend::Controller::Request

class Http extends Abstract
{
    // ...
}

Spot the problem? 'Abstract' is a reserved word in PHP. The same goes for interfaces. Consider this particularly aggregious example:


namespace Zend::View

abstract class Abstract implements Interface
{
    // ...
}

We've got two reserved words there: Abstract and Interface.

Stas, Dmitry, and I sat down to discuss this a few weeks ago to come up with a plan for migrating to PHP 5.3. In other OOP languages, such as Python, C#, interfaces are denoted by prefixing the interface with a capital 'I'; in the example above, we would then have Zend::View::IView. We decided this would be a sane step, as it would keep the interface within the namespace, and visually denote it as well. We also decided that this convention made sense for abstract classes: Zend::View::AView. So, our two examples become:


namespace Zend::Controller::Request

class Http extends ARequest
{
    // ...
}

and:


namespace Zend::View

abstract class AView implements IView
{
    // ...
}

Another thing that looks likely to affect OOP libraries and frameworks is autoloading, specifically when using exceptions. For instance, consider this:


namespace Foo::Bar

class Baz
{
    public function status()
    {
        throw new Exception(\"This isn't what you think it is\");
    }
}

You'd expect the exception to be of class Foo::Bar::Exception, right? Wrong; it'll be a standard Exception. To get around this, you can do the following:


namespace Foo::Bar

class Baz
{
    public function status()
    {
        throw new namespace::Exception(\"This is exactly what you think it is\");
    }
}

By using the namespace keyword, you're telling the PHP engine to explicitly use the Exception class from the current namespace. I also find this to be more semantically correct -- it's more explicit that you're throwing a particular type of exception, and makes it easy to find and replace these with alternate declarations at a later date.

I'd like to recommend other libraries adopt similar standards -- they're sensible, and fit already within PEAR/Horde/ZF coding standards. What say you?

blog comments powered by Disqus