Use autoloading and namespaces in PHP

PHP autoloading and namespaces provide handy conveniences with huge benefits.
1 reader likes this.
women programming

WOCinTech Chat. Modified by Opensource.com. CC BY-SA 4.0

In the PHP language, autoloading is a way to automatically include class files of a project in your code. Say you had a complex object-oriented PHP project with more than a hundred PHP classes. You'd need to ensure all your classes were loaded before using them. This article aims to help you understand the what, why, and how of autoloading, along with namespaces and the use keyword, in PHP.

What is autoloading?

In a complex PHP project, you're probably using hundreds of classes. Without autoloading, you'd likely have to include every class manually. Your code would look like this:

<?php

// manually load every file the whole project uses
require_once __DIR__.'/includes/SomeClass1.php';
require_once __DIR__.'/includes/SomeClass2.php';
require_once __DIR__.'/includes/SomeClass3.php';
require_once __DIR__.'/includes/SomeClass4.php';
require_once __DIR__.'/includes/SomeClass5.php';
require_once __DIR__.'/includes/SomeClass6.php';
require_once __DIR__.'/includes/SomeClass7.php';
require_once __DIR__.'/includes/SomeClass8.php';
require_once __DIR__.'/includes/SomeClass9.php';
require_once __DIR__.'/includes/SomeClass10.php';
// ... a hundred more times

$my_example = new SomeClass1();

This is tedious at best and unmaintainable at worst.

What if, instead, you could have PHP automatically load class files when you need it? You can, with autoloading.

PHP autoloading 101

It only takes two steps to create an autoloader.

  1. Write a function that looks for files that need to be included.
  2. Register that function with the spl_autoload_register() core PHP function.

Here's how to do that for the above example:

<?php
/**
 * Simple autoloader
 *
 * @param $class_name - String name for the class that is trying to be loaded.
 */
function my_custom_autoloader( $class_name ){
    $file = __DIR__.'/includes/'.$class_name.'.php';

    if ( file_exists($file) ) {
        require_once $file;
    }
}

// add a new autoloader by passing a callable into spl_autoload_register()
spl_autoload_register( 'my_custom_autoloader' );

$my_example = new SomeClass1(); // this works!

There you go. You no longer have to manually require_once every single class file in the project. Instead, with your autoloader, the system automatically requires a file as its class is used.

For a better understanding of what's going on here, walk through the exact steps in the above code:

  1. The function my_custom_autoloader expects one parameter called $class_name. Given a class name, the function looks for a file with that name and loads that file.
     
  2. The spl_autoload_register() function in PHP expects one callable parameter. A callable parameter can be many things, such as a function name, class method, or even an anonymous function. In this case, it's a function named my_custom_autoloader.
     
  3. The code is therefore able to instantiate a class named SomeClass1 without first having required its PHP file.

So what happens when this script is run?

  1. PHP realizes that there's not yet a class named SomeClass1 loaded, so it executes registered autoloaders.
     
  2. PHP executes the custom autoload function (my_custom_autoloader), and it passes in the string SomeClass1 as the value for $class_name.
     
  3. The custom function defines the file as $file = __DIR__.'/includes/SomeClass1.php';, looks for its existence (file_exists()), then (as long as the file is found) marks it as required with require_once __DIR__.'/includes/SomeClass1.php';. As a result, the class's PHP file is automatically loaded.

Huzzah! You now have a very simple autoloader that automatically loads class files as those classes are instantiated for the first time. In a moderately sized project, you've saved yourself from writing hundreds of lines of code.

What are PHP namespaces?

Namespaces are a way to encapsulate like functionalities or properties. An easy (and practical) analog is an operating system's directory structure. The file foo.txt can exist in both the directory /home/greg and in /home/other, but two copies of foo.txt cannot coexist in the same directory.

In addition, to access the foo.txt file outside of the /home/greg directory, you must prepend the directory name to the file name using the directory separator to get /home/greg/foo.txt.

You define a namespace at the top of a PHP file using the namespace keyword:

<?php

namespace Jonathan;

function do_something() {
    echo "this function does a thing";
}

In the above example, I've encapsulated the do_something() function within the namespace of Jonathan. This implies a number of things—most importantly, neither of those things conflicts with functions of the same name in the global scope.

For example, say you have the above code in its own file named jonathan-stuff.php. In a separate file, you have this:

<?php
require_once "jonathan-stuff.php";

function do_something(){  echo "this function does a completely different thing"; }

do_something();
// this function does a completely different thing

No conflict. You have two functions named do_something()they are able to co-exist with one another.

Now all you have to do is figure out how to access the namespaced methods. This is done with a syntax very similar to a directory structure, with backslashes:

<?php

\Jonathan\do_something();
// this function does a thing

This code executes the function named do_something() residing within the Jonathan namespace.

This method is also (and more commonly) used with classes. For example:

?php

namespace Jonathan;

class SomeClass { }

This can be instantiated like so:

<?php

$something = new \Jonathan\SomeClass();

With namespaces, very large projects can contain many classes that share the same name without any conflicts. Pretty sweet, right?

What problems do namespaces solve?

To see the benefits namespaces provide, you have only to look back in time to a PHP without namespaces. Before PHP version 5.3, you couldn't encapsulate classes, so they were always at risk of conflicting with another class of the same name. It was (and still is, to some degree) not uncommon to prefix class names:

<?php

class Jonathan_SomeClass { }

As you can imagine, the larger the code base, the more classes, and the longer the prefixes. Don't be surprised if you open an old PHP project some time and find a class name more than 60 characters long, like:

<?php 

class Jonathan_SomeEntity_SomeBundle_SomeComponent_Validator { }

What's the difference between writing a long class name like that and writing a long class name like \Jonathan\SomeEntity\SomeBundle\SomeComponent\Validator? That's a great question, and the answer lies in the ease of using that class more than once in a given context. Imagine you had to make use of a long class name multiple times within a single PHP file. Currently, you have two ways of doing this.

Without namespaces:

<?php

class Jonathan_SomeEntity_SomeBundle_SomeComponent_Validator { }
    
$a = new Jonathan_SomeEntity_SomeBundle_SomeComponent_Validator();
$b = new Jonathan_SomeEntity_SomeBundle_SomeComponent_Validator();
$c = new Jonathan_SomeEntity_SomeBundle_SomeComponent_Validator();
$d = new Jonathan_SomeEntity_SomeBundle_SomeComponent_Validator();
$e = new Jonathan_SomeEntity_SomeBundle_SomeComponent_Validator();

Oof, that's a lot of typing. Here it is with a namespace:

<?php
namespace Jonathan\SomeEntity\SomeBundle\SomeComponent;

class Validator { }

Elsewhere in the code:

<?php

$a = new \Jonathan\SomeEntity\SomeBundle\SomeComponent\Validator();
$b = new \Jonathan\SomeEntity\SomeBundle\SomeComponent\Validator();
$c = new \Jonathan\SomeEntity\SomeBundle\SomeComponent\Validator();
$d = new \Jonathan\SomeEntity\SomeBundle\SomeComponent\Validator();
$e = new \Jonathan\SomeEntity\SomeBundle\SomeComponent\Validator();

That certainly isn't much better. Luckily, there's a third way. You can leverage the use keyword to pull in a namespace.

The use keyword

The use keyword imports a given namespace into the current context. This allows you to make use of its contents without having to refer to its full path every time you use it.

<?php

namespace Jonathan\SomeEntity\SomeBundle\SomeComponent;

class Validator { }

Now you can do this:

<?php

use Jonathan\SomeEntity\SomeBundle\SomeComponent\Validator;

$a = new Validator();
$b = new Validator();
$c = new Validator();
$d = new Validator();
$e = new Validator();

Aside from encapsulation, importing is the real power of namespaces.

Now that you have an idea of what both autoloading and namespaces are, you can combine them to create a reliable means of organizing your project files.

PSR-4: The standard for PHP autoloading and namespaces

PHP Standard Recommendation (PSR) 4 is a commonly used pattern for organizing a PHP project so that the namespace for a class matches the relative file path to the file of that class.

For example, you're working in a project that makes use of PSR-4 and you have a namespaced class called \Jonathan\SomeBundle\Validator();. You can be sure the file for that class can be found in this relative location in the file system: <relative root>/Jonathan/SomeBundle/Validator.php.

Just to drive this point home, here are more examples of where a PHP file exists for a class within a project making use of PSR-4:

  • Namespace and class: \Project\Fields\Email\Validator()
    • File location: <relative root>/Project/Fields/Email/Validator.php
       
  • Namespace and class: \Acme\QueryBuilder\Where
    • File location: <relative root>/Acme/QueryBuilder/Where.php
       
  • Namespace and class: \MyFirstProject\Entity\EventEmitter
    • File location: <project root>/MyFirstProject/Entity/EventEmitter.php

This isn't actually 100% accurate. Each component of a project has its own relative root, but don't discount this information: Knowing that PSR-4 implies the file location of a class helps you easily find any class within a large project.

How does PSR-4 work?

PSR-4 works because it's achieved with an autoloader function. Take a look at one PSR-4 example autoloader function:

<?php

spl_autoload_register( 'my_psr4_autoloader' );

/**
 * An example of a project-specific implementation.
 *
 * @param string $class The fully-qualified class name.
 * @return void
 */
function my_psr4_autoloader($class) {
    // replace namespace separators with directory separators in the relative 
    // class name, append with .php
    $class_path = str_replace('\\', '/', $class);
    
    $file =  __DIR__ . '/src/' . $class_path . '.php';

    // if the file exists, require it
    if (file_exists($file)) {
        require $file;
    }
}

Now assume you've just instantiated the new \Foo\Bar\Baz\Bug(); class.

  1. PHP executes the autoloader with the $class parameter using the string value $class = "\Foo\Bar\Baz\Bug".
     
  2. Use str_replace() to change all backslashes into forward slashes (like most directory structures use), turning the namespace into a directory path.
     
  3. Look for the existence of that file in the location <relative root>/src/Foo/Bar/Baz/Bug.php.
     
  4. If the file is found, load it.

In other words, you change Foo\Bar\Baz\Bug to /src/Foo/Bar/Baz/Bug.php then locate that file.

Composer and autoloading

Composer is a command-line PHP package manager. You may have seen a project with a composer.json file in its root directory. This file tells Composer about the project, including the project's dependencies.

Here's an example of a simple composer.json file:

{
    "name": "jonathan/example",
    "description": "This is an example composer.json file",
    "require": {
        "twig/twig": "^1.24"
    }
}

This project is named "jonathan/example" and has one dependency: the Twig templating engine (at version 1.24 or higher).

With Composer installed, you can use the JSON file to download the project's dependencies. In doing so, Composer generates an autoload.php file that automatically handles autoloading the classes in all of your dependencies.

Screenshot of nested drop down menus highlighting the path example - vendor - twig - autoload.php

(Jonathan Daggerheart, CC BY-SA 4.0)

If you include this new file in a project, all classes within your dependency are automatically loaded, as needed.

PSR makes PHP better

Because of the PSR-4 standard and its widespread adoption, Composer can generate an autoloader that automatically handles loading your dependencies as you instantiate them within your project. The next time you write PHP code, keep namespaces and autoloading in mind.

Jonathan Daggerhart
Jonathan Daggerhart is a Drupal and WordPress developer who has worked with and contributed to both systems for over a decade. Owner and Architect at Daggerhart Lab. He has presented at multiple Drupal and WordPress camps on topics for both beginner and expert developers.

Comments are closed.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.