PHP
Article
By Moshe Teutsch

PHP Namespaces

By Moshe Teutsch
Last chance to win! You'll get a... FREE 6-Month Subscription to SitePoint Premium Plus you'll go in the draw to WIN a new Macbook SitePoint 2017 Survey Yes, let's Do this It only takes 5 min

Namespaces were a long awaited feature in PHP. While many other important features were released with PHP 5, namespaces were not supported until version 5.3. This led to various techniques for emulating them which, though necessary, were messy and confusing. Although namespaces have been part of PHP for over a year now, such techniques still exist. Many developers simply don’t know how to use proper namespaces in their code. In this article I will explain why namespaces are important and how you can use them in your own PHP code.

Why Use Namespaces?

Imagine you work for a small company that doesn’t have many employees. When talking about a co-worker, you refer to him by his first name. After an exceptionally successful year, your boss decides to double the number of employees. Suddenly, when you mention “Tom,” people are no longer sure to whom you are referring since there now a number of Toms at the office. To differentiate between them, you start using their last names too.

This metaphor illustrates the concept of namespaces. A namespace is a named container for identifiers such as class names and function names that you use in your programs. It groups them together and removes the possibility of name-clashes. In the example, the employees’ last names served as namespaces. Because family members are often grouped together, multiple Toms are able to co-exist without any ambiguity.

Large applications often have hundreds or thousands of components, which lead to a large number of name-clashes. Namespaces allow you to elegantly group components and avoid this problem.

Before namespaces were available, developers emulated them in object-oriented code by prefixing each component’s classes with a component name. For example, one standard was to join component and class names using underscores; the mail class in the blog component was named Blog_Mail. This practice led to many long, and sometimes confusing, class names. Consider the name of a class in the PHPUnit framework, PHPUnit_Framework_MockObject_Matcher_StatelessInvocation. This obviously isn’t ideal, which is why programmers needed proper support for namespaces in PHP.

Defining Namespaces

A namespace is defined with the namespace keyword and a name. It must be declared before any other code, with the exception of rarely used declare statements. Once defined, the scope of the namespace applies to the entire file.

<?php
namespace MyNamespace;
// ...

A namespace may alternatively be defined by wrapping brackets around its contents. No code is allowed outside the brackets except for the previously mentioned declare.

<?php
namespace MyNamespace {
    // ...
}

These two methods cannot be mixed, so choose one and stick to it.

Nested namespaces can be defined by separating each level with a backslash.

<?php
namespace MyProject\Blog\Admin;

Multiple namespaces may be defined in a single file by using the namespace keyword multiple times. In such instances, the scope of the preceding namespace ends once the next namespace definition appears.

<?php
namespace MyProject\Blog;
// following definitions are part of the MyProject\Blog namespace
// ...
namespace MyProject\Store;
// following definitions are now part of MyProject\Store
// ...

To set part of the file’s code in the global namespace, use the namespace keyword without a name. This feature can only be used in conjunction with the curly bracket syntax.

<?php
namespace My\Project {
    // My\Project namespace
    // ...
}
namespace {
    // Global namespace
    // ...
}

Referencing Namespaced Identifiers

Although any code can appear within the namespace, only classes, interfaces, functions and constants are affected by it. These identifiers can be referenced in one of three ways:

  1. Fully-qualified name
    A fully-qualified name is like an absolute path in a file system. It is the full name of the identifier; therefore there is no ambiguity about which identifier is being referenced. Fully-qualified names begin with a backslash. For example, My\Foo\Bar looks for the class Bar in the namespace My\Foo.
  2. Qualified name
    A qualified name is like a relative path in a file system. It contains only part of the name and resolves relative to the current namespace. For example, Foo\myFunction() in the namespace MyBaz resolves to \My\Baz\Foo\myFunction().
  3. Unqualified name
    An unqualified name is identical to a qualified name except it refers to the current namespace only and not to any sub-namespaces. For example, getPosts() in the namespace My\Foo\Blog resolves to Blog\getPosts(). If a function or constant is not found in the current scope, PHP won’t look for \My\Foo\getPosts(), rather it will just resolve the identifier to the global namespace.

Let’s look at an example. file1.php contains a couple of mock definitions namespaced as \MyProject\Blog.

<?php
namespace \MyProject\Blog;
class myClass {}
function myFunction() {}

Now file2.php declares the MyProject namespace, includes file1.php, and defines mock definitions that would seemingly conflict. The definitions don’t, though, because they live in separate namespaces. Then the file goes on to show examples of how fully-qualified, qualified, and unqualified names are resolved.

<?php
namespace \MyProject;
require_once "file1.php";
class myClass {}
function myFunction() {}

// fully-qualified names
\MyProject\myFunction();
\MyProject\Blog\myFunction(); 

// qualified name
\Blog\myFunction(); //resolves to \MyProject\Blog\myFunction();

// unqualified name
$test = new myClass(); // resolves to \MyProject\myClass
myFunction(); // resolves to \MyProject\myFunction

Notice that to reference classes and interfaces in the global namespace, you must begin their names with a backslash, i.e., use their fully-qualified name. This is not required for functions and constants unless an identifier with the same name is found in the current scope. To illustrate this, consider the following example:

<?php
namespace \Foo\Bar;
function file_exists($filename) { return true; }

// Incorrect: "Fatal error: Class '\Foo\Bar\ArrayObject' not found..."
$obj = new ArrayObject();
// Correct
$obj = new \ArrayObject();

// Doesn't need backslash; resolves to native function
echo strlen("Hello, world!");
// Resolves to dummy function, \Foo\Bar\file_exists()
echo file_exists('non-existent-file'); // True
// Resolves to real function
echo \file_exists('non-existent-file'); // False
--ADVERTISEMENT--

The use Keyword

In a large application that contains many, deeply-nested namespaces, it can become cumbersome to write out identifier names. To avoid this, you can import namespaces, classes and interfaces using the use keyword. This allows them to be referenced by an alias instead of their full name. use statements must be declared in the outermost scope of the file.

Here is an example:

<?php
use \Very\Long\Namespace;
use \Another\Long\Namespace\ClassName;

// resolves to \Very\Long\Namespace\aFunction();
Namespace\aFunction();
// resolves to \Another\Long\Namespace\ClassName
$obj = new ClassName();

Only unqualified and qualified names are affected by aliases; fully-qualified names are not. Therefore, the following will not be affected by the defined aliases:

<?php
$obj = new \ClassName();

To specify a specific alias, use the as keyword followed by the alias.

<?php
use \Very\Long\Namespace as MyNamespace;
// resolves to \Very\Long\Namespace\ClassName
$obj = new MyNamespace\ClassName();

For convenience, PHP lets you separate multiple namespace declarations with commas.

<?php
use \Very\Long\Namespace as MyNamespace,
    \Another\Long\Namespace\ClassName;

To explicitly use the current namespace and avoid aliases, use the namespace keyword before the identifier name.

<?php
// resolves to current namespace, not \Another\Long\Namespace\ClassName
$obj = new namespace\ClassName();

Dynamic Features

PHP offers some support for using namespaces dynamically, as well. The magic __NAMESPACE__ constant is defined by PHP at compile time and contains the current namespace as a string. In the global namespace, __NAMESPACE__ contains an empty string.

Namespaced identifiers can be dynamically referenced just like normal identifiers, with one exception: identifiers can only be referenced using fully-qualified names. For example:

<?php
$class = '\MyProject\Blog\MyClass';
$obj = new $class();

You should always escape backslashes when they are in double-quoted strings, since certain character combinations have special meanings. For example, “n” is the newline character, “t” is the tab character, etc. Failing to do so can lead to unexpected results. For example, the following code will not work as expected:

<?php
// "\n" in "\newFunction" seen as newline
$function = "\MyProject\Blog\newFunction";
$function(); // Fatal error: "Call to undefined function..."

The correctly escaped string is "\\MyProject\\Blog\\newFunction".

Summary

Namespaces are a powerful language feature that can be used to effectively group components in an application without fear of collision. This article covered the reasons why you should use namespaces and the syntax for defining and using them. You also saw how the use keyword allows you to alias namespaces, and how to use namespaced classes and functions dynamically. Now you should have a complete understanding of namespaces and be ready to start using them in your own applications.

More:
Login or Create Account to Comment
Login Create Account
Recommended
Sponsors
Get the most important and interesting stories in tech. Straight to your inbox, daily.Is it good?