PHP Namespaces and Autoloading

Namespaces

It’s important to understand how namespaces work in PHP, so I’d like to give a quick overview, as well as touch on a related feature, autoloading.

Some quick history of namespaces:

In PHP, all classes of course have class name, and there can only ever exist one class of the same name. For example, consider we had a class representing a varchar data type, we might want to call it class VarChar. However, suppose we then wanted one implementation for MySQL and another for PostrgeSQL. Since we can’t have two classes of the same name, a community standard evolved where we prefix class names using _, so we might then have classes like DB_MySQL_VarChar and DB_PostgreSQL_VarChar, which would have then been located in the files DB/MySQL/VarChar.php and DB/PostgreSQL/VarChar.php.

Developers then noticed two things about this:

  • The files are logically “namespaced” at the file system level, e.g. the DB/MySQL directory contains all MySQL related classes
  • At the PHP level, classes are all in the exact same namespace, can conflict with each other (although naming conventions help with that), and it’s annoying to have to type really long class names like DB_MySQL_VarChar all the time

Motivated by these reasons, namespaces were added. Essentially, namespaces just replace the underscores in class names with \, and add some language features that allow us to not have to type out the full class names all the time.

The most important concept to understand is the fully-qualified class name (FQCN). This is the complete name – the actual name – of a class, and is the namespace a class is in plus the class name. For example,

<?php
namespace DB\MySQL;
class VarChar {
}

<?php
class Foo {
}

The first class above is in the DB\MySQL namespace, so the FQCN of the above class is \DB\MySQL\VarChar. The second class is not in a namespace (i.e. it’s in the root namespace), so the FQCN is \Foo. Any time a class is used, PHP will always resolve it to its FQCN. You can think of the FQCN as the actual name of the class. Anywhere we use a class in PHP, we can refer to it by its FQCN. new \DB\MySQL\VarChar will work anywhere, and new \Foo will work anywhere (assuming the files have been included).

So far, we haven’t really addressed the original problem we had with long class names – we’ve just replaced a class called DB_MySQL_VarChar with one called \DB\MySQL\VarChar. To resolve this, PHP provides two different methods allowing us to use shorter class names and have PHP resolve these shorter classes to the FQCN.

1. Within a namespace, all classes used (and not prefixed with another namespace) are assumed to be in the same namespace.

For example:

<?php
namespace Foo\Bar;
$baz = new Baz;
$ex1 = new \Example;
$ex2 = new \Other\Example;

In the above, we’re in the namespace Foo\Bar, so PHP will resolve new Baz to new \Foo\Bar\Baz – i.e. it’s exactly the same as if we would have written new \Foo\Bar\Baz. The next two examples already specify a namespace, i.e. they start with a \, so PHP will not try to resolve them to a FQCN since we already specified the FQCN. $ex1 will be an instance of \Example and $ex2 an instance of \Other\Example.

2. Any use statements at the top of a file will be considered when resolving the FQCN. PHP will prefix any class usage with the current namespace.

<?php

namespace Foo\Bar;

use Other\SomeClass
use Other\SomeNamespace;

$class = new SomeClass; // FQCN resolves to \Other\SomeClass
$ex = new SomeNamespace\Foo; // FQCN resolves to \Other\SomeNamespace\Foo;

Note that a use statement has absolutely nothing to do with importing files or whether or not the file actually exists. use statements simply tell the PHP interpreter “when I say new SomeClass, I actually mean new \Other\SomeClass”.

That’s essentially all there is to namespaces. For full docs, see http://php.net/namespace. The key takeaway: every class has an FQCN which is the actual name of the class. Namespaces allow us to group classes together, and provide some functionality so we don’t have to write out the entire FQCN of the class.

With all of the above in mind, let’s think about some common errors we might run into when moving classes from no namespace (i.e. the root namespace, \) into a namespace. Consider the following example:

<?php
throw new Exception; // FQCN resolves this to \Exception;

If we then move this file into a namespace:

<?php
namespace Example;
throw new Exception; // FQCN now resolves to \Example\Exception.

To fix, we must specify the FQCN instead of letting PHP resolve it to the current namespace:

<?php
namespace Example;
throw new \Exception; // FQCN now resolves to \Exception.

Autoloading

Let’s now talk about a related feature, autoloading. The PHP interpreter can only execute a single PHP file at once, i.e. we run php foo.php at the command line or hit /foo.php in the browser, and a single file, foo.php, is executed. PHP then provides functionality for including other files, via require_once. If we want to use a class, we then need to include it. For example, if we wanted to use our DB\MySQL\VarChar class, we’d need to first include it:

<?php
require_once __DIR__ . '/DB/MySQL/VarChar.php';
$vc = new \DB\MySQL\VarChar;

Alternatively, we could use a use statement, but we still need to include the class:

<?php
require_once __DIR__ . '/DB/MySQL/VarChar.php';
use DB\MySQL\VarChar;
$vc = VarChar;

Now, it’s pretty cumbersome to have to type out a require statement every single time we want to use a class. To help with this, PHP implements a feature known as autoloading. This allows us to define a function (known as an autoloader or autoload function) that will get called whenever we attempt to use a class that does not exist. PHP will pass in the FQCN to the function. This is just an arbitrary function that’s up to us to implement. It could do anything, but what it it makes the most sense for is executing a require_once statement based on the given FQCN.

For example, it might look something like the following:

function autoload($fqcn) {
    $filename = str_replace('\\', '/', $fqcn); // \Foo\Bar => /Foo/Bar
    $filename = $filename . '.php'; /Foo/Bar => /Foo/Bar.php
    require_once __DIR__ . $filename;
}

In the above autoload function, we replace namespace separators with directory separates, and assume the filename matches the classname plus .php. Going back to our above example, and assuming the autoloader has been registered:

<?php
use DB\MySQL\VarChar;
$vc = VarChar;
// 1. PHP resolves this to the FQCN \DB\MySQL\VarChar.
// 2. PHP sees that the class \DB\MySQL\VarChar does not
//    exist, so it calls autoload('\DB\MySQL\VarChar');
// 3. autoload() includes the file, and we now have an
//    instance of \DB\MySQL\VarChar.

We follow a coding standard called PSR-2. This specifies a common way to name classes such that an autoload function knows how to find them. Composer then generates this autoload function for us (along with other autoload functions – not every composer packages follows PSR, so composer will generate an autoloader that handles all composer packages we’ve included in packages.json).