PHP Namespaces

Watch out! This tutorial is over 6 years old. Please keep this in mind as some code snippets provided may no longer work or need modification to work on current systems.
Tutorial Difficulty Level    

What are namespaces? In the broadest definition namespaces are a way of encapsulating items. This can be seen as an abstract concept in many places.

For example, in any operating system directories serve to group related files, and act as a namespace for the files within them. As a concrete example, the file foo.txt can exist in both directory /home/greg and in /home/other, but two copies of foo.txt cannot co-exist in the same directory. In addition, to access the foo.txt file outside of the /home/greg directory, we must prepend the directory name to the file name using the directory separator to get /home/greg/foo.txt. This same principle extends to namespaces in the programming world!

In the PHP world, namespaces are designed to solve two problems that authors of libraries and applications encounter when creating re-usable code elements such as classes or functions:

  1. Name collisions between code you create, and internal PHP classes/functions/constants or third-party classes/functions/constants.
  2. Ability to alias (or shorten) Extra_Long_Names designed to alleviate the first problem, improving readability of source code.

PHP Namespaces provide a way in which to group related classes, interfaces, functions and constants. Here is an example of namespace syntax in PHP:

<?php
namespace my\name; // see "Defining Namespaces" section

class MyClass {}
function myfunction() {}
const MYCONST = 1;

$a = new MyClass;
$c = new \my\name\MyClass; // see "Global Space" section

$a = strlen('hi'); // see "Using namespaces: fallback to global
                   // function/constant" section

$d = namespace\MYCONST; // see "namespace operator and __NAMESPACE__
                        // constant" section
$d = __NAMESPACE__ . '\MYCONST';
echo constant($d); // see "Namespaces and dynamic language features" section
?>

NoteNamespace names are case-insensitive.

Although any valid PHP code can be contained within a namespace, only the following types of code are affected by namespaces: classes (including abstracts and traits), interfaces, functions and constants.

Namespaces are declared using the namespace keyword. A file containing a namespace must declare the namespace at the top of the file before any other code – with one exception: the declare keyword.

<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }

?>

The only code construct allowed before a namespace declaration is the declare statement, for defining encoding of a source file. In addition, no non-PHP code may precede a namespace declaration, including extra whitespace:

<html>
<?php
namespace MyProject; // fatal error - namespace must be the first statement in the script
?>

In addition, unlike any other PHP construct, the same namespace may be defined in multiple files, allowing splitting up of a namespace’s contents across the filesystem.

Example Usage

Let’s take Karani–it’s a CRM with a financial component, so it tracks donors and receipts, among many other things.

Let’s set Karani as our top-level namespace (sort of like the parent folder–usually named after your app or package). This might have some classes related to Contacts, and some related to Billing, so we’re going to create a sub-namespace for each, Karani\Billingand Karani\Contacts.

Let’s make a class or two in each:

<?php namespace Karani\Billing;

class Receipt {}
<?php namespace Karani\Billing;

class Subscription{}
<?php namespace Karani\Contacts;

class Donor {}

So, we’re picturing a directory structure like this:

Karani
    Billing
        Receipt
        Subscription
    Contacts
        Donor

Referencing other classes in the same namespace

So, if a Subscription can send a Receipt, it’s easy to refer to it:

<?php namespace Karani\Billing;

class Subscription
{
    public function sendReceipt()
    {
        $receipt = new Receipt;
    }
}

Since Receipt is in the same namespace as Subscription, you can just refer to it like you would if you weren’t using namespaces.


Referencing other classes in different namespaces

OK, but what if I want to reference a Receipt inside of a Donor?

<?php namespace Karani\Contacts;

class Donor
{
    public function sendReceipt()
    {
        // This won't work!
        $receipt = new Receipt;
    }
}

ou guessed it: This won’t work.

We’re in the Karani\Contacts namespace, so when we wrote new Receipt, PHP assumes we’re talking about Karani\Contacts\Receipt. But that class doesn’t exist, and that’s not what we’re looking for.

So, you’ll get a Class Karani\Contacts\Receipt not found error.

You might be tempted to modify it to instead say $receipt = new Karani\Billing\Receipt–but even that won’t work. Since we’re in the Karani\Contacts namespace right now, it’s seeing anything you write as being relative to the namespace you’re in. So that would try to load a class named Karani\Contacts\Karani\Billing\Receipt, which also clearly doesn’t exist.

Instead, you have two options:

First, you can precede it with a slash to create its FQCN (Fully Qualified Class Name): $receipt = new \Karani\Billing\Receipt;, which sends the signal to PHP to escape out of the current namespace before looking for this class.

If you precede the full namespace with a slash, creating the FQCN, you can refer to this class anywhere in your app without worrying about your current namespace.

Or, Second, you can use the class at the top of the file, and then just reference it as Receipt:

<?php namespace Karani\Contacts;

use Karani\Billing\Receipt;

class Donor
{
    public function sendReceipt()
    {
        $receipt = new Receipt;
    }
}

As you can tell, use imports a class from a different namespace into this namespace so we can refer to it more easily. Once you’ve imported the class, any time you reference Receipt in this class, it’ll assume you’re pointing to the imported class.

More on PHP Namespaces in a future tutorial….