Namespaces exist in many languages, including C++ and the Java™ programming language. They came about to help with the organization of large codebases, where oftentimes, there was a concern for overlapping function or class names with the application and the problems that having that would cause. The use of namespaces can help identify what function or utility the code provides, or even help specify its origin. An example of this is the System namespace within C#, which contains all the functions and classes provided by the .NET framework.
In other languages without formal namespaces (such as PHP V5.2 and earlier), people would often emulate namespaces by trying to use a specific naming convention within the class or function names. The Zend Framework does this, where each of the class names begin with Zend, and each child namespace is separated by an underscore. For example, the class definition Zend_Db_Table is a class that is part of the Zend Framework and has database functionality. One issue with this approach is that the resulting code can become verbose, especially if the class or function is several layers deep (Zend_Cache_Backend_Apc is an example of this from the Zend Framework). Another issue is that all code must conform to this style, which can be difficult if you're integrating third-party code within an application that doesn't conform to this naming convention.
The history of namespaces in PHP is quite a winding road. They were originally going to be a part of PHP V5, but they were removed in the development stages since proper implementation could not be achieved. They finally came back to life as a part of PHP V6, then moved to PHP V5.3 after the decision to move all of the nonunicode enhancements to another PHP V5.x release was made in 2007. While much of the behavior of namespaces has been constant since the original design, the issue of which operator to use was the biggest one, with polarizing views on what it should be from all members of the community. A final decision to use the backslash as the operator was made in October 2008, solving all the issues that using various other operators presented in terms of language design and usability.
Namespaces in PHP
PHP borrows much of the syntax and design of namespaces from other languages — most notably C++. However, it does deal with namespaces somewhat uniquely in some circumstances, which can be a stumbling block for users expecting namespaces to work exactly the same as other languages. In this section, we look at how namespaces work in PHP.
Defining a namespace
Defining a new namespace is fairly trivial. To do so, add the following line in Listing 1 as the first command or output in a file.
Listing 1. Defining a namespace
<?php
namespace Foo;
class Example {}
?>It's important to understand that the above declaration of namespace must be the first command or output in the file. Having anything else before it will result in a fatal error. Listing 2 shows some examples of this.
Listing 2. Bad ways to define a namespace
/* File1.php */
<?php
echo "hello world!";
namespace Bad;
class NotGood {}
?>
/* File2.php */
<?php
namespace Bad;
class NotGood {}
?>In the first part of Listing 2, we attempted to echo out to the console before the namespace definition, which results in a fatal error. In the second part of the listing, we added an extra space before the <?php opening tag, which also causes a fatal error. It's important to watch for this situation as we write our code since it is a common mistake when working with namespaces in PHP.
However, both of the above examples can be rewritten by separating out the namespace definition and the code that is to be a part of the namespace declaration into its own separate file, which can be included in the original files. Listing 3 demonstrates this.
Listing 3. Fixing the bad ways to define a namespace
/* Good.php */
<?php
namespace Good;
class IsGood() {}
?>
/* File1.php */
<?php
echo "hello world!";
include './good.php';
?>
/* File2.php */
<?php
include './good.php';
?>Now that we saw how to define a namespace for the code within a file, let's see how to leverage this namespaced code within an application.
Using namespaced code
Once we have defined a namespace and put code inside of it, we can use it very easily within an application. There are different options for calling a namespaced function, class, or constant. One way is to explicitly reference the namespace as a prefix to the call. Another option is to define an alias for the namespace and prefix the call with that, which is designed to make the namespace prefix shorter. And finally, we can simply just use the namespace within our code, which makes it the default namespace and, by default, makes all calls reference that. Listing 4 illustrates the differences between the calls.
Listing 4. Calling a function within a namespace
/* Foo.php */
<?php
namespace Foo;
function bar()
{
echo "calling bar....";
}
?>
/* File1.php */
<?php
include './Foo.php';
Foo/bar(); // outputs "calling bar....";
?>
/* File2.php */
<?php
include './Foo.php';
use Foo as ns;
ns/bar(); // outputs "calling bar....";
?>
/* File3.php */
<?php
include './Foo.php';
use Foo;
bar(); // outputs "calling bar....";
?>Listing 4 demonstrates the different ways to call a function bar() in namespace Foo. In File1.php, we see how to make the explicit call, prefacing the call with the namespace name. File2.php uses an alias to the namespace name, so we substitute the namespace name with the alias. Finally, File3.php simply uses the namespace, which allows us to make the call to bar() without any prefix.
We can also define more than one namespace within a file by adding further namespace calls in the file. Listing 5 illustrates this.
Listing 5. Multiple namespaces in a file
<?php
namespace Foo;
class Test {}
namespace Bar;
class Test {}
$a = new Foo\Test;
$b = new Bar\Test;
var_dump($a, $b);
Output:
object(Foo\Test)#1 (0) {
}
object(Bar\Test)#2 (0) {
}Now that we have the basics of how to make a call inside a namespace, let's see some more complicated namespace situations and how those calls work.
Namespace resolution
One of the hurdles to getting the hang of namespaces is learning how the scope resolution works. While simple cases like those in Listing 4 make sense, the problem comes when we begin to nest namespaces within each other, or when we are in one namespace and are looking to make calls against the global space. PHP V5.3 has rules on resolving these issue automatically in a sensible way.
Let's create a few include files, with each one having the function hello() defined within it.
Listing 6. Function hello() defined in different namespaces
/* global.php */
<?php
function hello()
{
echo 'hello from the global scope!';
}
?>
/* Foo.php */
<?php
namespace Foo;
function hello()
{
echo 'hello from the Foo namespace!';
}
?>
/* Foo_Bar.php */
<?php
namespace Foo/Bar;
function hello()
{
echo 'hello from the Foo/Bar namespace!';
}
?>Listing 6 defines the function hello() three times in three different scopes: in the global scope, in the Foo namespace, and in the Foo/Bar namespace. Depending upon the scope in which the hello() function call is made determines which hello() function is called. An example of how these calls look is shown below. Here, we'll use the Foo namespace to see how to call the hello() function in the other namespaces.
Listing 7. Calling all of the hello() functions from the Foo namespace
<?php include './global.php'; include './Foo.php'; include './Foo_Bar.php'; use Foo; hello(); // outputs 'hello from the Foo namespace!' Bar\hello(); // outputs 'hello from the Foo/Bar namespace!' \hello(); // outputs 'hello from the global scope!' ?>
We can see that we can shorten the namespace prefix when referencing a child namespace within the current namespace (the Foo/Bar/hello() call can be shortened to Bar/hello()). And we see how to specify that we wish to call the method in the global scope by just prefacing the call with the namespace operator.
Now that we have the mechanics of how namespaces work, let's see how we can use them within our code.
Use cases for namespaces in PHP
The overall goal for namespaces is to help us better organize our code by eliminating the amount of definitions that live within the global scope. In this section, we'll take a look at a few examples where having namespaces can help achieve these goals with minimal effort.
Namespacing third-party code
Many PHP applications use code from different sources, whether it be consistently designed code like what exists in the PEAR repository, code from various frameworks like CakePHP or the Zend Framework, or other code found from various places on the Internet. One of the biggest problems when integrating this code is that it may not mix very well with existing code; function or class names may clash with what we are using already in our application.
One example of this is the PEAR Date package. It uses the class name Date, which is a fairly generic class name and could very well exist in other places in our code. So a good way to get around this is by adding a simple namespace command to the top of the Date.php file inside the package. Now we can be specific when we wish to use the PEAR Date class instead of our own.
Listing 8. Using the PEAR Date class as defined in a namespace
<?php
require_once('PEAR/Date.php');
use PEAR\Date; // the name of the namespace we've specified in PEAR/Date.php
// since the current namespace is PEAR\Date, we don't need to prefix the namespace name
$now = new Date();
echo $now->getDate(); // outputs the ISO formatted date
// this example shows the full namespace specified as part of the class name
$now = new PEAR\Date\Date();
echo $now->getDate(); // outputs the ISO formatted date
?>We've defined the PEAR Date class inside namespace PEAR/Date within the PEAR/Date.php file, so all we need to do is include that code in our file and use the new namespace, or prefix the class or function names with the namespace name. With this, we can include third-party code in our application safely.
Name clashing isn't just an issue with third-party code. It can also existing with large codebases that have parts never intended to get near each other. In the next section, we see how namespaces can simplify this situation.
Avoid utility function name clashing
Just about every PHP application has a number of utility methods. They aren't really part of any of the objects in the application, and they don't really have a fit in any one place in the application, although they do serve a role to the application as a whole. But they can cause maintenance headaches as our application grows.
One place where this can be a problem is with unit testing, where we write code that tests the code that runs an application. Most unit-testing suites are designed to run every test in the entire test suite. For example, we could have two utility files that would never get included together, but in the test suite, they are, since we are testing the entire application at once. While designing an application in such a way is never a good idea for long-term maintenance, it often exists in large legacy codebases.
Listing 9 shows how to avoid this. We have two files, utils_left.php and utils_right.php, which are collections of utility functions for right- and left-handed users. For each file, we define each in its own namespace.
Listing 9. utils_left.php and utils_right.php
/* utils_left.php */
<?php
namespace Utils\Left;
function whichHand()
{
echo "I'm using my left hand!";
}
?>
/* utils_right.php */
<?php
namespace Utils\Right;
function whichHand()
{
echo "I'm using my right hand!";
}
?>We define a whichHand() function that outputs which hand we are using. In Listing 10, we see how easy it is to safely include both files and switch between the namespaces we wish to call.
Listing 10. Example of using utils_left.php and utils_right.php together
<?php
include('./utils_left.php');
include('./utils_right.php');
Utils\Left\whichHand(); // outputs "I'm using my left hand!"
Utils\Right\whichHand(); // outputs "I'm using my right hand!"
use Utils\Left;
whichHand(); // outputs "I'm using my left hand!"
use Utils\Right;
whichHand(); // outputs "I'm using my right hand!"Now both files can be included safely together, and we specify which namespace to use to handle our function call. And the impact on our existing code is minimal, since the re-factoring to support this only requires us to add the use statement at the top of the file to indicate which namespace to use.
This same idea can be extended beyond our defined PHP code. In the next section, we see how we can even override internal functions in a namespace.
Overriding internal function names
While oftentimes, the internal functions in PHP provide great utility, sometimes they don't do exactly what we want them to. We may need to augment their behavior to match what we want the function to do, but we also want to redefine the function with another name to avoid further cluttering the scope.
The filesystem functions are one area where we may want to do this. Let's say we want to make sure any file created by file_put_contents() has certain permissions set. For example, let's say we want the files created by this to be read-only; we can redefine the function in a new namespace, as shown below.
Listing 11. Defining file_put_contents() inside a namespace
<?php
namespace Foo;
function file_put_contents( $filename, $data, $flags = 0, $context = null )
{
$return = \file_put_contents( $filename, $data, $flags, $context );
chmod($filename, 0444);
return $return;
}
?>We call the internal file_put_contents() function inside the function and prefix the function name with a backslash to indicate that it should be handled in the global scope, which means the internal function will be called. After calling the internal function, we then chmod() the file to set the appropriate permissions.
These are just a few examples of how we can use namespaces to enhance our code. In each case, we avoid doing ugly hacks, such as prefixing the name of the function or class to make the name unique. We also now know how using namespaces can make it much safer to include third party code in large applications without the worry of name collisions.
Summary
Namespaces in PHP V5.3 are a welcome addition to the language, helping developers organize code within an application in a sensible way. They enable you to avoid using naming standards to handle namespacing, allowing you to write more efficient code. While they have been a long time coming, namespaces are a welcome addition for any large-scale PHP application suffering name clashes.
Resources
Learn
- Start this series with "What's new in PHP V5.3, Part 1: Changes to the object interface" and "Part 2: Closures and Lambda functions." Then continue with "What's new in PHP V5.3, Part 4: Creating and using Phar archives."
- Learn more about closures in Wikipedia.
- See the original RFC for lambda functions and closures for more details on how closures work.
- Read "A PHP V5 migration guide" to learn how to migrate code developed in PHP V4 to V5.
- "Connecting PHP Applications to Apache Derby" shows you how to install and configure PHP on Windows® (some steps are applicable to Linux®).
- PHP.net is the central resource for PHP developers.
- Check out the "Recommended PHP reading list."
- Browse all the PHP content on developerWorks.
- Expand your PHP skills by checking out IBM developerWorks' PHP project resources.
- To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
- Using a database with PHP? Check out the Zend Core for IBM, a seamless, out-of-the-box, easy-to-install PHP development and production environment that supports IBM DB2 V9.
- Stay current with developerWorks' Technical events and webcasts.
- Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
- Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
- Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
Get products and technologies
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- Participate in developerWorks blogs and get involved in the developerWorks community.
- Participate in the developerWorks PHP Forum: Developing PHP applications with IBM Information Management products (DB2, IDS).
Comments
Dig deeper into Open source on developerWorks
developerWorks Premium
Exclusive tools to build your next great app. Learn more.
developerWorks Labs
Technical resources for innovators and early adopters to experiment with.
IBM evaluation software
Evaluate IBM software and solutions, and transform challenges into opportunities.
