Namespacing in PHP

It's been a bumpy ride, in regards to namespace support in PHP. Thankfully, it was added to the language in PHP 5.3, and the applicable structure of PHP code has improved greatly since then. But how exactly do we use them?


What's a Namespace?

"Don't forget to escape the backslash when you store a namespace name in a string!"

Imagine a namespace as a drawer in which you can put all kinds of things: a pencil, a ruler, a piece of paper and so forth. These are your belongings. Directly underneath your drawer is someone else's, and he puts the same things in it. To avoid using each other's items, you decide to label the drawers so it's clear what belongs to whom.

Previously, developers had to use underscores in their classes, functions and constants to separate code bases. That's equivalent to labeling each others belongings and putting them in one big drawer. Sure, it's at least some kind of organization, but it's very inefficient.

Namespacing to the rescue! You can declare the same function, class, interface and constant definitions in separate namespaces without receiving fatal errors. Essentialy, a namespace is nothing more than a hierarchically labeled code block holding regular PHP code.

You are Using Them!

It is important to keep in mind that you indirectly make use of namespaces; as of PHP 5.3, all the definitions which are not yet declared in a user defined namespace fall under the global namespace.

The global namespace also holds all internal PHP definitions, like echo(), mysqli_connect(), and the Exception class. Because the global namespace has no unique identifying name, its most often referred to as the global space.

Note that it's not an obligation to use namespacing.

Your PHP script will work perfectly fine without them, and this behavior isn't about to change very soon.


Defining a Namespace

A namespace definition is the first statement the PHP interpreter should encounter in a PHP file. The only statement allowed to occur above a namespace declaration is a declare statement, and then again, only if it declares the encoding of the script.

Declaring a namespace is as simple as using the namespace keyword. A namespace name should obey the same rules as other identifiers in PHP. Therefore, a namespace must start with a letter or underscore, followed by any number of letters, numbers, or underscores.

If you want to assign a code block to the global space, you use the namespace keyword without appending a name.

You are allowed to have multiple namespaces in the same file.

You can also scatter the same namespace throughout different files; the process of file inclusion automatically merges them. Therefore, it's a good coding practice to limit the amount of namespace definitions to one per file, just like you would do with classes.

Namespacing is used to avoid conflicting definitions and introduce more flexibility and organization in your code base.

Note that the brackets surrounding the namespace code block are completely optional. In fact, sticking to the one-namespace-per-file rule and omitting the curly brackets makes your code a lot cleaner--there's no need to indent the nested code.

Sub-namespaces

Namespaces can follow a certain hierarchy, much like the directories in the file system on your computer. Sub-namespaces are extremely useful for organizing the structure of a project. For example, if your project requires database access, you might want to put all the database-related code, such as a database exception and connection handler, in a sub-namespace called Database.

To maintain flexibility, it is wise to store sub-namespaces in sub-directories. This encourages structuring of your project and makes it much easier to use autoloaders that follow the PSR-0 standard.

PHP uses the backslash as its namespace separator.


Fun fact: in the RFC to decide which namespace separator should be used, they even considered using a smiley.

You can have as many sub-namespaces as you want.

Defining sub-namespaces with nested code blocks is not supported. The following example will throw a very descriptive fatal error: "Namespace declarations cannot be nested".


Calling Code from a Namespace

If you want to instantiate a new object, call a function or use a constant from a different namespace, you use the backslash notation. They can be resolved from three different view points:

  • Unqualified name
  • Qualified name
  • Fully qualified name

Unqualified Name

This is the name of a class, function or constant without including a reference to any namespace whatsoever. If you are new to namespacing, this is the view point you are used to working from.

Qualified Name

This is how we access the sub-namespace hierarchy; it makes use of the backslash notation.

The example below throws a fatal error: "Fatal error: Class 'MyProject\Database\MyProject\FileAccess\Input' not found" because MyProject\FileAccess\Input is approached relatively to the namespace you are currently in.

Fully Qualified Name

The unqualified and qualified names are both relative to the namespace you are currently in. They can only be used to access definitions on that level or to dive deeper into the namespace hierarchy.

If you want to access a function, class or constant residing at a higher level in the hierarchy, then you need to use the fully qualified name--an absolute path rather than relative. This boils down to prepending your call with a backslash. This lets PHP know that this call should be resolved from the global space instead of approaching it relatively.

It's not required to use the fully qualified name of internal PHP functions. Calling an unqualified name for a constant or function which does not exist in the namespace you are currently working in results in PHP searching the global namespace for them. This is a built-in fallback which does not apply to unqualified class names.

With this in mind, we can now overload internal PHP functions whilst still being able to call the original function (or constant for that matter).

Dynamic calls

PHP is a dynamic programming language; so you can also apply this functionality for calling namespaced code. This is essentially the same as instantiating variable classes or including variable files. The namespace separator PHP uses is also a meta character in strings. Don't forget to escape the backslash when you store a namespace name in a string!

The namespace Keyword

Not only is the namespace keyword used to define a namespace, it can also be used to explicitly resolve to the current namespace, functionally similar to the self keyword for classes.

The __NAMESPACE__ constant

Much like the self keyword cannot be used to determine what the current class name is, the namespace keyword cannot be used to determine what the current namespace is. This is why we have the __NAMESPACE__ constant.

This constant is very useful for learning if you are just starting out with namespaces; it is also helpful for debugging. As it is a string, it can also be used in combination with dynamic code calls which we previously discussed.


Aliasing or Importing

"it's not an obligation to use namespacing"

Namespacing in PHP has support for importing. Importing is also referred to as aliasing. Only classes, interfaces, and namespaces can be aliased or imported.

Importing is a very useful and fundamental aspect of namespacing. It gives you the ability to make use of external code packages, like libraries, without having to worry about conflicting names. Importing is achieved by using the use keyword. Optionally, you can specify a custom alias with the as keyword.

How it's Done

A fully qualified name can be aliased to a shorter unqualified name so that you don't have to write its fully qualified name each time you want to make use of it. Aliasing or importing should occur in the highest scope of a namespace or in the global scope. Trying to do this in the scope of a method or function is invalid syntax.

Alternatively, you can alias to it a different name:

You are also allowed to import global classes, like the Exception class. When imported, you don't have to write its fully qualified name anymore.

Note that import names are not resolved as relative to the current namespace but from an absolute standpoint, starting at the global space. This means that a leading backslash is unnecessary and not recommended.

Though it is possible to dynamically call namespaced code, dynamic importing is not supported.


Conclusion

Namespacing is used to avoid conflicting definitions and introduce more flexibility and organization in your code base. Remember that you are not obligated to use namespacing; it's a feature used in combination with an object oriented workflow. Hopefully, however, you will consider taking your (future) PHP project to the next level by making use of namespacing. Have you decided yet?

Tags:

Comments

Related Articles