php[architect] logo

Want to check out an issue? Sign up to receive a special offer.

PHP 5.3 namespaces for the rest of us

Posted by on March 29, 2010

According to the official documentation, PHP namespaces have been designed to prevent name collisions between classes from different packages and to avoid the use of very long names in the code to refer to classes or functions—nobody really wants to have to deal with something called Zend_Db_Adapter_Mysqli or PHPUnit_Framework_Constraint_IsInstanceOf, after all. This means that namespaces help a developer write code that is both more concise and clearer—a direction which is always an improvement towards expressiveness.

Within the PHP implementation of namespaces, these names will be ideally refactored to Zend\Db\Adapter\Mysqli and PHPUnit\Framework\Constraint\IsInstanceOf, where \ is the namespace separator. In the codebase, however, there will typically be very few references to these classes with their fully qualified name, because it is possible to import entire namespaces in a script and then use the class names directly, making the code easier to follow and unambiguous to write.

In fact, the definition of a namespace class itself does not contain its fully qualified name. For example, this would be the source file of an hypothethical MyLibrary\TypeOfComponents\MyClass class:

<?PHP
namespace MyLibrary\TypeOfComponents;

class MyClass
{
    // ...
}

The convention when writing namespace-enabled code is that of creating a folder structure that reflects the individual components of a namespace (for example, MyClass would be in the MyLibrary/TypeOfComponents directory. This helps standardizing the autoloading process.

How namespaces work

Namespaced name resolution has been retrofitted in PHP 5.3 by inserting a processing mechanism at compile time. All the references to classes and functions in a namespaced source file are parsed before the actual execution of the PHP script and substituted with fully qualified names.

But what rules does the name resolution process follow? You can better understand this process with a filesystem metaphor:

  • Every name that does not start with a backslash is interpreted as a relative reference (path) from the current namespace (directory). For example, in the source code above, MyClass would refer to MyLibrary\TypeOfComponent\MyOtherClass with the unqualified name MyOtherClass. It can also refer to MyLibrary\TypeOfComponents\SubNamespace\ACollaborator with the qualified name SubNamespace\ACollaborator.
  • Names that start with a backslash are always relative to the global namespace (to the root directory), and are always resolved to the literal specified value. For example, \PHPUnit\Framework\TestCase class is resolved to the fully qualified name of PHPUnit\Framework\TestCase.

Note that the name resolution process examples above are limited to classes, but the same concepts apply to methods.

Pre-PHP 5.3 code will not, of course, have any namespace defined in it and will continue to work as before, residing in the global namespace because there are no namespace keywords.

Fallback

There is however an exception to the resolution process I have just described: constants and functions that are defined in the global namespace—including all built-in PHP functions like is_array() and strlen().

If we had to refer to each function using its fully-qualified name and prefix them with a backslash every time we need to use them, our code would pretty soon become an unreadable jumble of symbols. For example, you’d have to write \strlen() in all namespaced code, because the strlen() function is defined in the global namespace, and not in the current one.

Luckily, function and constant name resolution falls back to the global namespace when they are not found in a more specific one that is currently available. Thus, you can call strlen() from namespaced code without using a leading backslash—as long, of course, as you do not have a strlen() function defined in the current namespace that will shadow the global one.

This fallback rule does not apply to classes and interfaces: SPL‘s constructs such as Iterator and ArrayObject, for example, must be written as \Iterator and \ArrayObject in namespaced code, or they won’t work.

You can think of this rule as having these functions defined in your PATH environment variable: no one refers to the ls (dir at a Windows shell prompt) command as /bin/ls.

Importing classes

Being able to refer to classes in the current namespace without their fully qualified name is a good improvement over the long class names we had to deal with before namespaces, but we can expand the name aliasing further.

Import statements that create aliases to fully qualified names can be inserted after the namespace keyword, which is always the first language construct at the beginning of the file when present. These aliases are local to the file. Consider this example:

<?PHP
namespace MyLibrary;

use ExternalLibrary\Filter\Int as IntFilter;
use ExternalLibrary\Filter\NotEmptyString;

In a source file with these use statements, you can refer to the IntFilter and NotEmptyString classes without any syntax noise. If an explicit alias is not defined, the base name (NotEmptyString) is used as a default value, and it is usually sufficient.

Again, we can extend the filesystem metaphor to cover the import functionality. Aliases can be compared to symlinks from the current directory to an absolute path: you are able to refer to the symlink with a short base name instead of using a long absolute path.

Importing class and function names makes namespace very efficient to employ. The fully qualified name of an external class is hidden from the source code and extracted at the top of the file: if it changes, it is easy enough to update a single instruction instead of refactoring large areas of code. Moreover, with this approach the external dependencies are explicitly listed in a single point for every source file.

Dynamic features

Name resolution happens at compile time; therefore, every time a class is referenced dynamically, such as when using a variable variable or passing a parameter to (for example) class_exists(), you must be a fully qualified class name:

$instance = new $class();
$boolean = class_exists($class);
$boolean = $instance instanceof $class;

In these use cases, by the time the code is executed, the resolution process will have already occurred and, obviously, the compiler will have no way of telling whether $class contains a class reference that must be resolved; therefore you must make sure that it contains a full-qualified class name in order for things to work properly.

Despite their simplicity, some of the less-obvious aspects of namespaces can be difficult to understand when you’re first starting out. If you have any other doubts, you can read the FAQ from the official manual, which contain much more code than my examples, or ask a question in the comments.


Marco is the keeper of keys and Chief Garbage Collector at Blue Parabola. He can be found on Twitter as @mtabini.
Tags: , , , , ,
 

Responses and Pingbacks

Related blog post from Cal Evans on the namespace code converter developed by Zend for Zend Framework: http://blog.calevans.com/2010/03/27/zends-new-namespace-converter/

Nice comparison!

The filesystem comparison is also used in the official manual but they overspecify by talking about qualified and unqualified names while they’re really the same thing in practice (relative paths).

Have been waiting for this for a while. This should help create stand alone modules in our web development. The big question in my mind is are we going to see this revised significantly in the near future. Any thoughts?

All namespace should be in lowercase please.

Currently there is a proposed standard for lowercase namespaces, but the only nearly production ready project that uses name I know ignores it (Doctrine 2). It is not even used in the other documents of the standards group: http://groups.google.com/group/php-standards/web/psr-0-final-proposal

I don’t see what problem name spaces actually fix.

[…] post ha sido creado a partir del artículo PHP 5.3 Namespaces (en inglés). Posted on 31 Mar 2010 – by SirViejo In: php Tags: namespace, namespaces, […]

To look in detail about the name spaces of PHP 5.3, it is bit odd when we see in a normal view. But one who is familiar with frameworks like Zend / Doctrine and following the class name structures like Doctrine_Record will now feel the difference while defining classes.

Still it is only useful for people who tries to follow standards described by Zend and uses it for the purpose it is created, the rest sees it odd and useless.

Really there is a long way to improve PHP.

Quoting: I don’t see what problem name spaces actually fix.

Let say, two programmers wrote two classes each named Image_Class
but they performed different functions, To avoid any conflicts, you would give them each there own namespace. so you could not use one without the correct namespace declaration.

boyhowdy i was confuzed when you said compile time versus run-time, cuz php is just a runtime thingy, so i waaaasted some time on stackoverflood trying to find out the difference, then gave up and just came back here to think it ovr.

so compile time is like when the php engine is figuring out where all the “stuff” is, setting things up to be ready to run the functions, then run-time is when all the functinos get rund, and the vars get sitted and echod. it kind of all happens when the script is rund, it’s not compiled and saved to a file the you run at the curser.

so then namespace is like setting a var equal to the path where this class is stored on disk. so that happens at compile time, right before the code is rund.

then when the code is rund, some majik autoload function can use this namespace var to figure out the path to the file where the class is stored on disk, and say “hey, include dis file located at dis path”

so the autoload is an easyer way than having to type a million include statement that point to files where your class is stored.

and the namespace makes it so you don’t have to give your class or function a superlong name like main_program_photo_section_album_collection_show_list_of_photo_albums

well if that’s klose to bein rite let me know.
i gotta go, Betsy said she’s got an unexpected t_encapsed_and_whitespace, which probably means she’s gotta see a dentist

Oh my god, thanks a lot for pointing this one out !
This sure as hell will save some time and headakes in the long run !

HI,

I am using PHP/5.3.2-1ubuntu4.10. I am getting error while working with namespace feature of the php.

Leave a comment

Use the form below to leave a comment: