What's new in PHP V5.3, Part 3: Namespaces

PHP V5.3 is scheduled to release soon. This "What's new in PHP V5.3" series covers new and exciting features in this release. Part 1 of the series looks at the changes made to the object oriented programming and object handling in PHP 5.3. Part 2 looks at lambda functions and closures. Here in Part 3, we look at namespaces, which is one of the most anticipated and the most debated feature in this release of PHP. The concept of namespaces provides a way to help avoid problems with multiple functions, classes, and constants of the same name being defined multiple times.

Share:

John Mertic, Software Engineer, SugarCRM

John Mertic graduated with a degree in computer science from Kent State University and is currently a software engineer at SugarCRM. He has contributed to many open source projects, most notably PHP projects; he is the creator and maintainer of the PHP Windows Installer.



20 January 2009

Also available in Russian Japanese Vietnamese

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

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

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=363483
ArticleTitle=What's new in PHP V5.3, Part 3: Namespaces
publish-date=01202009