PHPBuilder - Introducing Namespaces for PHP Developers



RSS Twitter
Articles Application Architecture

Introducing Namespaces for PHP Developers

by: PHP Builder Staff
|
September 21, 2011

PHP's historical lack of namespace support has long been a sore spot for developers residing both within and without the PHP community. Lacking the ability to efficiently organize project libraries, PHP developers have long made do with various contrived hacks, including notably using an autoloader in conjunction with code organized within a nested folder structure. Such an approach is used by the PHP Extension and Application Repository (PEAR), as well as by popular frameworks such as the Zend Framework.

The inclusion of namespace support within PHP 5.3 effectively brought the need for gripes and workarounds to a halt, however adoption of this exciting new feature has seemed surprisingly slow in the more than two years since its release. To be certain, a fair amount of dust was kicked up over the feature implementation (see Michael Kimsal's blog post on the topic and notably the ensuing comments for just a sampling of the angst), however the utility of this new feature is simply undeniable. Therefore I thought it would be worthwhile to offer a formal introduction to namespaces for the benefit of those PHP developers who haven't yet had the opportunity to investigate the topic.

What Is a Namespace?

To understand the utility of namespacing, it seems most effective to consider one of the many inconvenient situations which could arise when namespaces aren't used. You've been hard at work on a rather complex web application which plugs into multiple social networks, among them Facebook and Twitter. Ever the lazy programmer, you spend some time researching existing open source libraries before settling upon two which look particularly promising. After having downloaded both and incorporated them into your application using the require_once() statement:

require_once 'facebook.class.php';
require_once 'twitter.class.php';

After tinkering with a few unrelated application changes, you reload the page within the browser only to be met with the following error:

Cannot redeclare class Account in /var/www/dev.example.com/library/twitter.class.php

So what happened? As coincidence has it, both library developers created a class named Account. While convenient for them, such a generic class title greatly increases the likelihood of a name collision.

Having grown wise to such inevitabilities, PHP developers devised the aforementioned workaround involving an autoloader and nested directory structure. This approach works by examining the name of the instantiated class, translating its underscores to a path. For instance, consider a refactored Twitter library which uses this approach. The library might be nested like this:

WJG/
  Twitter/
    Account.php
    Search.php 

Although such an approach was ubiquitous within the PHP community prior to PHP 5.3, it isn't without drawbacks. Notably when used in conjunction with an autoloader, developers must refer to inconveniently long class names, such as:

class WJG_Twitter_Account {
  ...
}

While the above example isn't so terrible, given a complex library it is easy for such a convention to quickly run amok. For instance here is an example from the Zend Framework's Zend_CodeGenerator component:

class Zend_CodeGenerator_Php_Docblock_Tag_Return extends Zend_CodeGenerator_Php_Docblock_Tag {
...
}

PHP 5.3's namespace feature does away with the need for such tedious workarounds. Read on to learn how!

PHP 5.3's Namespace Syntax

Using the namespace keyword you can effectively organize your code using unique identifiers. Returning to the Facebook and Twitter libraries, if I were the author of both I might namespace each using WJGFacebook and WJGTwitter, respectively. These namespaces are defined before anything else in the respective files, like this:

<?php

namespace WJGTwitter;

class Account
{
  function __construct() {
    echo "In Twitter Account constructor";
  }
}

...

<?php

namespace WJGFacebook;

class Account
{
  function __construct() {
    echo "In FB Account constructor";
  }
}

Technically speaking, the PHP manual defines these to be sub-namespaces; there is nothing to stop you from simply using Facebook as your namespace title, however keep in mind we are striving towards ensuring each library is unique, and therefore prefixing the namespace with a top-level company name or similarly unique title seems like a wise idea.

Incorporating the Namespaced Library Into Your PHP Application

With the namespace in place, the previously encountered collisions go away, because you'll now be referencing the class in relation to its namespace designation. This can be done by using the class' fully qualified name, as demonstrated here:

require_once 'facebook.class.php';
require_once 'twitter.class.php';

$account = new WJGTwitterAccount();

While this approach works fine, it doesn't really help resolve the goal of using shorter, more convenient names. Therefore you might consider an alternative approach, which involves aliasing, or importing, the namespace using the use statement:

require_once 'twitter.class.php';
require_once 'facebook.class.php';

use WJGTwitter as TW;

$account = new TWAccount();

In this example we are creating an alias, or abbreviation for the WJGTwitter namespace, allowing us to instead refer to merely TW when identifying the namespace. In doing so, we can use the much shorter TWAccount() to instantiate the Twitter library's Account class.

Conclusion

If you're new to namespaces, hopefully even this short series of examples have been suffice to get you thinking about how to more effectively organize your code! Be sure to check out the PHP manual's namespace documentation, as it discusses a number of rules and other caveats not described here. As always if you have any questions be sure to contact me!

Comment and Contribute

Your comment has been submitted and is pending approval.

Author:

Comment:



Comment:

(Maximum characters: 1200). You have characters left.