Feb 7, 2015 | php, namespaces

A Brief Introduction to PHP Namespacing

!
Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

A bit of history

In PHP prior to 5.3 (2009), any class you define lived at the same global level as other classes.

Class User, class Contact, class StripeBiller--they're all together in the global namespace.

This may seem simple, but it makes organization tough, which is why PHP developers started using underscores to separate their class names. For example, if I were developing a package called "Cacher", I might name the class Mattstauffer_Cacher so as to differentiate it from someone else's Cacher--or Mattstauffer_Database_Cacher, to differentiate it from an API cacher.

That worked decently, and there were even autoloading standards that separated out the underscores in class names for folders on the file system; for example, Mattstauffer_Database_Cacher would be assumed to live in the file Mattstauffer/Database/Cacher.php.

An autoloader is a piece of code that makes it so that, instead of having to require or include all of the files that contain your class definitions, PHP knows where to find your class definitions based on a particular convention.

But it was pretty messy, and often ended up with class names like Zend_Db_Statement_Oracle_Exception and worse. Thankfully, in PHP 5.3, real namespaces were introduced.

The basics of namespaces

Namespaces are like a virtual directory structure for your classes. So class Mattstauffer_Database_Cacher could become class Cacher in the Mattstauffer\Database namespace:

<?php

class Mattstauffer_Database_Cacher {}

is now:

<?php namespace Mattstauffer\Database;

class Cacher {}

And we would refer to it elsewhere in the app as Mattstauffer\Database\Cacher.

A real example

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\Billing and 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;
    }
}

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

Use blocks and Fully-Qualified Class Names

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.

Aliasing

But, what if you also have a Receipt class in your current namespace? What if your class needs access to both Karani\Contacts\Receipt and Karani\Billing\Receipt?

You can't just import the Karani\Billing\Receipt class, or you won't be able to use both--they'd both have the same name in this class.

Instead, you'll need to alias it. You can change the use statement to something like use Karani\Billing\Receipt as BillingReceipt;. Now you've aliased the class, and then you can refer to the imported class as BillingReceipt throughout your class.

PSR-0/PSR-4 Autoloading

You know the folder analogy I just used above?

It's easy to think about your classes that way, but there's actually not any inherent connection between your namespaces and your files' structure. Unless you use an autoloader, PHP doesn't have any idea where those classes actually live in your directory structure.

Thankfully, PSR-0 (now deprecated) and PSR-4 are autoloading standards that actually map your namespaces to real folders. So, if you're using PSR-0 or PSR-4--which is extremely likely if you're using Composer or any modern framework-- and a compatible autoloader, you can assume that the classes actually are in folders.

Composer and PSR-4 Autoloading

So, let's say I want the Karani namespace to live in my src folder.

Here's my folder structure for a generic, framework-independent project:

app
public
src
    Billing
    Contacts
vendor

As you can see, the src folder represents the Karani top level namespace. Since I'm using Composer as my autoloader, all I need to do to get my application to autoload my classes is teach Composer how to map namespaces to folders. Let's do that using PSR-4.

I'm going to open up composer.json and add a PSR-4 autoload section:

{
    "autoload": {
        "psr-4": {
            "Karani\\": "src/"
        }
    }
}

So you can see: the left side is the namespace that we're defining (note that you need to escape the slash separators here by doubling them), and the right side is the directory.

Conclude.

As you can see, there's a lot going on here, but it's really pretty simple: 98% of the time, you're going to be working with a PSR-4-structured, Composer-autoloaded, set of classes.

So 98% of the time, you can check your composer.json, figure out where the root of the top level namespace lives, and assume you'll then have a one-to-one map of your namespace and the folders/files in that directory. Done.

And remember: next time you get Class SOMETHING not found, you probably just need to remember to import it with a use statement at the top of your file.


Comments? I'm @stauffermatt on Twitter


Tags: php  •  namespaces

Subscribe

For quick links to fresh content, and for more thoughts that don't make it to the blog.