Leveraging PHP V5.3 namespaces for readable and maintainable code

Organize your code and protect yourself from name collision

Should you be using namespaces in your PHP application development? In this article, get an overview of namespace syntax, learn best practices for its use, and see a miniature sample Model-View-Controller application that uses namespaces.

Share:

Don Denoncourt, Author, Consultant

Don DenoncourtDon Denoncourt is a free-lance consultant, trainer, mentor, and author specializing in Java technology, Groovy, Grails, and PHP. You can reach him at dondenoncourt@gmail.com.



01 March 2011

Also available in Chinese Japanese Portuguese

"Conan is my role model." If I make that statement at the dinner table, my son would immediately think that I pattern myself after Conan the Barbarian, whereas my wife would think I want to be like the late-night talk show host, Conan O'Brien. This context confusion is known in IT as name collision. Many languages have a strategy to circumvent name collision and, with V5.3, so does PHP. PHP solves the name collision problem with its new namespaces feature. Of course, the names on which PHP resolves collision are not the names of people but rather the names of classes, functions, and constants.

This article explains why you should consider using namespaces on your next project. It provides an overview of namespace semantics, provides best practices, and offers a sample Model-View-Controller (MVC) application that uses namespaces. The article then discusses namespace support in Eclipse, NetBeans, and Zend Studio, with specific instructions on using namespaces with Eclipse.

Do I need namespaces?

A strength of the PHP language is its simplicity. So if you are new to PHP, namespaces are yet another concept you will need to understand. But if any of the following are true, you should consider their use:

  • You are developing a large application with hundreds of PHP files.
  • Your application is being developed by a team of coders.
  • You are planning on using frameworks that use PHP V5.3 and namespaces.
  • You have used namespaces (or comparable functionality, such as packages) in other languages, such as the Java™, Ruby, or Python languages.

If you are the sole developer of relatively small applications, namespaces may not be for you. But for the rest of us, namespaces provides a clean way to organize class structures and, of course, prevent name collision. These two reasons are why many framework developers are adopting the use of namespaces. Zend Framework (the 800-pound gorilla of PHP frameworks), for example, is using namespaces in Zend Framework V2.0.


A quick overview

A namespace provides a context for a name. For example, the two classes shown in Listing 1 have name collision.

Listing 1. Two classes with the same name cause collision without namespaces
class Conan {
	var $bodyBuild = "extremely muscular";
	var $birthDate = 'before history';
	var $skill = 'fighting';
}

class Conan {
	var $bodyBuild = "very skinny";
	var $birthDate = '1963';
	var $skill = 'comedy';
}

To specify a namespace, you simply add a namespace declaration as the first statement in the source, as shown in Listing 2.

Listing 2. Two classes of the same name but with namespaces resolves collision
<?php
namespace barbarian;
class Conan {
	var $bodyBuild = "extremely muscular";
	var $birthDate = 'before history';
	var $skill = 'fighting';
}
namespace obrien;
class Conan {
	var $bodyBuild = "very skinny";
	var $birthDate = '1963';
	var $skill = 'comedy';
}
$conan = new \barbarian\Conan();
assert('extremely muscular born: before history' == 
   "$conan->bodyBuild born: $conan->birthDate");

$conan = new \obrien\Conan();
assert('very skinny born: 1963' == "$conan->bodyBuild born: $conan->birthDate");
?>

The above code runs fine, but before I describe why the two Conans work well together, let me point out two things. First, I'm using assertions to prove that the code works as expected. And second, I'm doing something you should never do: declaring multiple namespaces in one source file.

The namespace provides a unique qualifier for the two Conans. The code clearly states when I'm referring to the burly destroyer or the late-night talk show host. Notice that the syntax for the instantiation uses a backslash (\) followed by the namespace name:

$conan = new \barbarian\Conan();

and:

$conan = new \obrien\Conan();

Those qualifiers kind of look like Windows®-style directory qualifiers, which is not a bad way to think about them because, for one, namespaces support both relative and absolute references (just like directories), and for another, it is a best practice to put the source for your class files in directories that match the namespaces.


Using namespaces

It would be more real-world to separate the two Conan classes into directories called barbarian and obrien, and then reference those classes from other PHP files. There are three ways to reference a PHP namespace:

  • Prefix the class name with the namespace
  • Import the namespace
  • Alias the namespace

To use the first option, you simply prefix the class name with the namespace (after, of course, you the include the source file):

include "barbarian/Conan.php";
$conan = new \barbarian\Conan();

That's pretty straightforward, but the issue with option one's strategy is that, given a large application, you will be constantly retyping the namespace. And besides all that typing, you are needlessly cluttering up your code base. With option two, you import the namespace with the PHP V5.3 reserved word use:

include "barbarian/Conan.php";
use barbarian\Conan;  
$conan = new Conan();

Option three lets you specify an alias for the namespace:

include "barbarian/Conan.php";
use \barbarian\Conan as Cimmerian;
$conan = new Cimmerian();

(Cimmerian, by the way, is yet another moniker Conan the Barbarian is known by.)

One issue I have with all three of the above examples is the use of the include statement. You can remove the need for the includes by using an __autoload function. The PHP magic method __autoload function is called whenever a class is referenced that has not yet been included in the source file. Place the code in Listing 3 in a file called autoload.php.

Listing 3. A magic __autoload function dynamically includes source files
<?php
function __autoload($classname) {
  $classname = ltrim($classname, '\\');
  $filename  = '';
  $namespace = '';
  if ($lastnspos = strripos($classname, '\\')) {
    $namespace = substr($classname, 0, $lastnspos);
    $classname = substr($classname, $lastnspos + 1);
    $filename  = str_replace('\\', '/', $namespace) . '/';
  }
  $filename .= str_replace('_', '/', $classname) . '.php';
  require $filename;
}
?>

Then import autoload.php into your source:

require_once "autoload.php"; 
use \barbarian\Conan as Cimmerian;

The big advantage of the auto-loader is that you won't have to create an include statement for every class. Note that although PHP's namespaces can be used for functions and constants as well as classes, the auto-loader technique only works for classes. The auto-loader is so handy that rather than coding functions, you can create methods in a appropriately named utility class and put your constants in immutable classes.


Getting real with MVC

Leaving O'Brien to ridicule The Destroyer while being slain, let's move on to a simple example MVC application. To benefit from namespaces, you should design your naming conventions before keying a line of code. A common best practice is to use a namespace tree. Understand that namespaces have high-level namespaces and sub-namespaces. If your company has multiple applications, it might be handy to have a high-level namespace that is your company name. Then, you would use a sub-namespace for the application. Next, you'd have a level that contains directories that in turn have names that specify the application functionality of the PHP classes contained therein. For example, let's say the high-level company namespace is denoncourt, the first sub-level is retail, and the third level has functional names, as shown in Listing 4.

Listing 4. A design for namespaces can include nested sub-namespaces
/denoncourt
	/retail
		/common
		/controller
		/model
		/utility
		/view

The controller, model, and view sub-namespaces are obviously for the MVC architecture, but the utility and common sub-namespaces I threw in to be used for general classes that didn't cleanly fit in one of the other sub-namespaces.

Let's jump right into the code for the mini-MVC application. Listing 5 provides the code for index.php, which is placed in the root folder.

Listing 5. The MVC application's index PHP uses the controller class
<?php
require "autoload.php";
use denoncourt\retail\controller as Control;
$controller = new Control\Controller();
$controller->execute();
?>

Notice the long namespace and the use of the alias name of Control. The use of aliases is my preferred method for using namespaces for two reasons: First, if I later rename the namespace, I only have one line of code to change per source file. And second, given that it is a best practice to fully qualify your namespace as you instance classes, my use of Control\Controller() is effectively the same thing as \denoncourt\retail\controller\Controller(). Note that I could have just as well created an alias for a higher-level namespace, and then used the names of the sub-namespace for the class instantiation:

use denoncourt\retail as Retail;
$controller = new retail\controller\Controller();

This is a handy feature for those times when you will be referring to multiple levels of your namespace in the same source file. In the denoncourt/retail/controller directory, I created Controller.php, which is shown in Listing 6.

Listing 6. The MVC controller class predicates action based on user input
<?php
namespace denoncourt\retail\controller;
use denoncourt\retail as retail;

class Controller {
  public function execute() {
    switch ($_GET['action']) {
    case 'showItem' :
      $item = new retail\model\Item();
      require "denoncourt/retail/utils/format.php";
      require "denoncourt/retail/view/item.php";
      break;
    }
  }
}
?>

In denoncourt/retail/model, I created Item.php. Listing 7 shows the code.

Listing 7. The MVC Item class is in the model sub-namespace
<?php
namespace denoncourt\retail\model;
class Item {
  public $itemNo = '123';
  public $price = 2.45;
  public $qtyOnHand = 87;
}
?>

In denoncourt/retail/utils, I created format.php, which is shown Listing 8.

Listing 8. The dollar PHP shows how a function can also be namespaced
<?php
namespace denoncourt\retail;
function dollar($dollar) {
    return "\$$dollar";
}
?>

Note that, as stated earlier, I would have preferred to put the format function in a utility class (so the auto-loader would handle the import of the code and I wouldn't have had to code the require statement for format.php).

Finally, the item.php view page is in denoncourt/retail/views. Listing 9 shows the code.

Listing 9. The item page displays the model instanced in the controller
<html>
<head>
<style>
dt {
  float:left; clear:left;
  font-weight:bold;
  margin-right:10px;
  width:15%;
  text-align: right;
}
dd { text-align:left; }
</style>
</head>
<body>
<dl>
  <dt>Item No:</dt><dd><?php echo "$item->itemNo"; ?></dd>
  <dt>Price:</dt><dd>
       <?php echo \denoncourt\retail\dollar($item->price); ?>
       </dd>
  <dt>Quantity On Hand:</dt><dd><?php echo "$item->qtyOnHand"; ?></dd>
</dl>
</body>
</html>

Notice how the item page qualifies the dollar function with \denoncourt\retail\ namespace.


Fall back

If a source file has a namespace declaration, then all references to classes, functions, and constants use the namespace semantics. When PHP encounters an unqualified class, function, or constant, it does what is know as fallback. A fallback on a user class causes the compiler to assume the current namespace. To refer to non-namespaced classes, you need to put a lone backslash. For example, to refer to PHP Exception class, you would use $error = new \Exception();. Keep that in mind as you use any of the Standard PHP Library classes (such as ArrayObject, FindFile, and KeyFilter).

For functions and constants, if the current namespace does not contain that function or constant, PHP's fallback mechanism will fall back to the standard PHP function. So, for example, if you've coded your own strlen function, PHP would resolve to your function. But, if you also wanted to use the standard PHP strlen function (say, within your own strlen implementation), you'd need to precede the function invocation with a backslash, as Listing 10 shows.

Listing 10. PHP standard functions can be qualified with a backslash to identify the global namespace
<?php
namespace denoncourt\retail;
function strlen($str) {
    return \strlen();
}
?>

The namespace global variable and strings

If you like to code dynamic methods, you may be tempted to place a namespace in a double-quoted string: "denoncourt\retail\controller". But remember that you'll need to escape those slashes: "denoncourt\\retail\\controller". One workaround is simply to use single quotation marks: 'denoncourt\retail\controller'.

As you do your dynamic programming, keep in mind that PHP V5.3 has a new global variable called __NAMESPACE__. Consider using the global variable rather than typing it:

$echo 'I am using this namespace:'.__NAMESPACE__;

IDE support for namespaces

Most of the major IDEs already have support for PHP V5.3. NetBeans V6.8 has great support for namespaces. Not only does it have code completion but it also makes suggestions for improving your code with best practices. For example, it is a best practice with PHP namespaces to fully qualify your namespaces within your code using with absolute references rather than relative references. If you key code that uses relative namespace qualifiers, NetBeans displays a light bulb icon in the left-most code margin. If you hover over the icon, NetBeans shows a tool tip describing the suggested change. And if you then click the icon, NetBeans makes the code change for you.

Zend Studio provides similar capabilities. If you are reticent to begin using namespaces, consider upgrading your IDE and try out namespaces with a bit of help from your favorite IDE. Note that you may find that you don't even have to upgrade your IDE, as many of them have provided PHP V5.3 features for more than a year now.

PHP Development Tools (PDT) V2.1 also has solid support for namespaces. PDT is a plug-in for Eclipse. A link to the installation notes for PDT is provided in the Resources section.

To enable namespace support, I first had to tell Eclipse/PDT to use PHP V5.3. To do that, from the application main menu, click Window > Preferences, as Figure 1 shows. Expand PHP in the tree pane, then choose PHP Interpreter. Then, change the PHP version to PHP 5.3, and click OK.

Figure 1. The Eclipse PDT plug-in requires you to set the interpreter to PHP V5.3
Set the interpreter to V5.3

You can create a PHP project by clicking File > New Project, expanding the PHP node, and then clicking PHP Project. To create a PHP file, simply right-click the project in PHP Explorer, then click PHP file. PDT uses appropriate syntax highlighting for the namespace keywords of namespace and use (see Figure 2).

Figure 2. PDT uses syntax highlighting for namespace keywords and displays namespaces in the PHP Explorer and Outline views
Image showing how PHP uses syntax highlighting

It's handy to have PDT show you the namespaces in the PHP Explorer and Outline views, as it helps you visualize how your namespaces are assigned to various classes. PDT also provides something we've come to expect with IDEs: code completion (see Figure 3). Code completion is invoked by PHP while keying the use statement.

Figure 3. PDT provides code completion for namespaces
Screenshot showing a list of namespace options for code completion in a code listing

PDT will also pop up a code completion window while you key class names. For example, if I type new Item, PDT will also show a window listing Item � denoncourt\retail\item.

When I select denoncourt\retail\item, PDT inserts the required use statement and the qualifier on the instantiation line:

use denoncourt\retail\model;
new model\Item();

What's cool is when I type new Conan, PDT also shows a window listing:

	Conan � obrien
	Conan � barbarian

Allowing me to select the appropriate Conan. And now that I've wandered back to my infatuation with the two Conans, perhaps it is time to wrap things up.


Wrapping up

If you are still hesitant to get started with namespaces, before you put off learning namespaces for another year, I suggest you load your favorite IDE with PHP V5.3 support and give namespaces a whirl. As to naming conventions, it's more important to set some simple ones than to agonize over coming up with the perfect strategy. Personally, with a long background in Java development, I like to follow the Java naming conventions. I use camel-cased names for my PHP namespaces and stay away from the underscores. By using namespaces in your next PHP project, your code will be cleaner and more organized. You will become acquainted with a facility that is common to most leading languages. And you will be prepared for using the wealth of frameworks already using PHP V5.3 — and namespaces in particular.


Download

DescriptionNameSize
Sample scriptsos-php-5.3namespaces_code.zip6KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=629355
ArticleTitle=Leveraging PHP V5.3 namespaces for readable and maintainable code
publish-date=03012011