"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.
Back to top
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.
Back to top
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 include
s 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.
Back to top
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.
Back to top
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();
}
?>
Back to top
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__;
Back to top
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
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
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
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.
Back to top
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.
Back to top
Download