Advertisement
  1. Code
  2. PHP

Namespacing in PHP

Scroll to top
10 min read

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.

1
<?php 
2
namespace MyProject {
3
    // Regular PHP code goes here, anything goes!

4
    function run() 
5
    {
6
        echo 'Running from a namespace!';
7
    }
8
}

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

1
<?php 
2
namespace {
3
    // Global space!

4
}

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

1
<?php
2
namespace MyProject {
3
}
4
5
namespace MySecondProject {
6
}
7
8
namespace {
9
}

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.
1
// myproject/database/connection.php
2
<?php 
3
namespace MyProject\Database
4
5
class Connection {
6
    // Handling database connections

7
}

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

1
<?php 
2
namespace MyProject\Blog\Auth\Handler\Social;
3
4
class Twitter {
5
    // Handles Twitter authentification

6
}

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".

1
<?php
2
namespace MyProject {
3
    namespace Database {
4
        class Connection { }
5
    }
6
}

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.

1
<?php
2
namespace MyProject;
3
4
class MyClass {
5
    static function static_method()
6
    {
7
        echo 'Hello, world!';
8
    }
9
}
10
11
// Unqualified name, resolves to the namespace you are currently in (MyProject\MyClass)

12
MyClass:static_method();

Qualified Name

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

1
<?php
2
namespace MyProject;
3
4
require 'myproject/database/connection.php';
5
6
// Qualified name, instantiating a class from a sub-namespace of MyProject

7
$connection = new Database\Connection();

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.

1
<?php
2
namespace MyProject\Database;
3
4
require 'myproject/fileaccess/input.php';
5
6
// Trying to access the MyProject\FileAccess\Input class

7
$input = new MyProject\FileAccess\Input();

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.

1
<?php
2
namespace MyProject\Database;
3
4
require 'myproject/fileaccess/input.php';
5
6
// Trying to access the MyProject\FileAccess\Input class

7
// This time it will work because we use the fully qualified name, note the leading backslash

8
$input = new \MyProject\FileAccess\Input();

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).

1
<?php
2
namespace MyProject;
3
4
var_dump($query); // Overloaded

5
\var_dump($query); // Internal

6
7
// We want to access the global Exception class

8
// The following will not work because there's no class called Exception in the MyProject\Database namespace and unqualified class names do not have a fallback to global space

9
// throw new Exception('Query failed!');

10
11
// Instead, we use a single backslash to indicate we want to resolve from global space

12
throw new \Exception('ailed!');
13
14
function var_dump() {
15
    echo 'Overloaded global var_dump()!<br />';
16
}

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!

1
<?php
2
namespace OtherProject;
3
4
$project_name = 'MyProject';
5
$package_name = 'Database';
6
$class_name = 'Connection';
7
8
// Include a variable file

9
require strtolower($project_name . '/'. $package_name .  '/' . $class_name) . '.php';
10
11
// Name of a variable class in a variable namespace. Note how the backslash is escaped to use it properly

12
$fully_qualified_name = $project_name . '\\' . $package_name . '\\' . $class_name;
13
14
$connection = new $fully_qualified_name();

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.

1
<?php
2
namespace MyProject;
3
4
function run() 
5
{
6
    echo 'Running from a namespace!';
7
}
8
9
// Resolves to MyProject\run

10
run();
11
// Explicitly resolves to MyProject\run

12
namespace\run();

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.

1
<?php
2
namespace MyProject\Database;
3
4
// 'MyProject\Database'

5
echo __NAMESPACE__;

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.

1
use [name of class, interface or namespace] as [optional_custom_alias]

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.

1
<?php
2
namespace OtherProject;
3
4
// This holds the MyProject\Database namespace with a Connection class in it

5
require 'myproject/database/connection.php';
6
7
// If we want to access the database connection of MyProject, we need to use its fully qualified name as we're in a different name space

8
$connection = new \MyProject\Database\Connection();
9
10
// Import the Connection class (it works exactly the same with interfaces)

11
use MyProject\Database\Connection;
12
13
// Now this works too! Before the Connection class was aliased PHP would not have found an OtherProject\Connection class

14
$connection = new Connection();
15
16
// Import the MyProject\Database namespace

17
use MyProject\Database;
18
19
$connection = new Database\Connection()

Alternatively, you can alias to it a different name:

1
<?php
2
namespace OtherProject;
3
4
require 'myproject/database/connection.php';
5
6
use MyProject\Database\Connection as MyConnection;
7
8
$connection = new MyConnection();
9
10
use MyProject\Database as MyDatabase;
11
12
$connection = new MyDatabase\Connection();

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.

1
<?php
2
namespace MyProject;
3
4
// Fatal error: Class 'SomeProject\Exception' not found

5
throw new Exception('An exception!');
6
7
// OK!

8
throw new \Exception('An exception!');
9
10
// Import global Exception. 'Exception' is resolved from an absolute standpoint, the leading backslash is unnecessary

11
use Exception;
12
13
// OK!

14
throw new Exception('An exception!');

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

1
<?php
2
namespace OtherProject;
3
4
$parser = 'markdown';
5
6
// This is valid PHP

7
require 'myproject/blog/parser/' . $parser . '.php';
8
9
// This is not

10
use MyProject\Blog\Parser\$parser;

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?

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.