Working well with a Laravel codebase requires solid understanding of how composer autoloading and class namespaces work.

In this article we will cover PSR-4 class autoloading through php composer and the related concept of class namespaces.

By the end of the article you should be able to read and understand any php codebase that uses autoloading.

Project directory setup

Create a new php project directory named autoload and move into the project directory:

mkdir autoload
cd autoload

Create the basic php project structure:

mkdir app
touch index.php
touch composer.json

The index.php file is our application bootstrap file that starts the execution of our php code.

Autoload setup

Add the following to the composer.json file:

{
  "autoload": {
    "psr-4": {
      "App\\": "app/"
    }
  }
}

The json above maps the App root namespace to the app root directory in our project.

Any php class files in the app directory will have the App namespace.

With the autoload map in place we can run the composer dump-autoload command to generate the vendor/autoload.php file:

composer dump-autoload -o

Display the project directory structure with the tree command:

tree

The result:

.
├── app
├── composer.json
├── index.php
└── vendor
    ├── autoload.php
    └── composer
        ├── ClassLoader.php
        ├── LICENSE
        ├── autoload_classmap.php
        ├── autoload_namespaces.php
        ├── autoload_psr4.php
        ├── autoload_real.php
        └── autoload_static.php

We can see that the composer dump-autoload command created the vendor directory and the vendor/autoload.php file.

This vendor/autoload.php file will be used to autoload any classes added to the app directory or one of its subdirectories.

Using the autoload file

The final step of the autoloading setup is to use the generated the autoload.php file in our index.php bootstrap file.

Add the following to the index.php file:

<?php

require_once __DIR__ . "/vendor/autoload.php";

// TODO add PHP code here

That is all that is needed to start using auto loaded php classes under the app directory.

Auto loaded class example

First create a class file named Greeting.php directly in the app directory:

touch app/Greeting.php

All auto loaded class file names must begin with an uppercase letter.

Add the following to the new app/Greeting.php file:

<?php

namespace App;

class Greeting
{
    public function sayHello()
    {
        return "Hello";
    }
}

The autoloading configuration in the composer.json file maps the root App namespace to the root app directory.

Therefore the Greeting class that is directly inside the app directory will be in the App namespace as specified by the namespace App declaration at the top of the file.

The namespace declaration in the class file must match the PSR-4 autoloading configuration in the composer.json file.

Using the Greeting class

Lets now use the class in our index.php file by changing the content of the index.php file to:

<?php

require_once __DIR__ . "/vendor/autoload.php";

echo (new \App\Greeting)->sayHello();
echo (new \App\Greeting)->sayHello();

This example uses two separate instances of the fully namespace qualified class name (FQN) \App\Greeting to print the text Hello twice.

Run the index.php bootstrap file using the php command:

php index.php

You should see the output:

HelloHello

Alternatively instead of typing the FQN of the class each time, we can use the namespace of the class using the use <namespace>\<class> statement:

<?php

require_once __DIR__ . "/vendor/autoload.php";

use App\Greeting;

echo (new Greeting)->sayHello();
echo (new Greeting)->sayHello();

Using one class from another

We can also use one class from within another class.

First create a second class file named Audience.php also directly in the app directory:

touch app/Audience.php

Add the following to the app/Audience.php file:

<?php
namespace App;

class Audience
{
   public function toWorld()
   {
       return "World";
   }
}

The namespace of this class is also App since it is directly in the app directory.

Now modify the content of the app/Greeting.php file to use the Audience class:

<?php

namespace App;

class Greeting
{
    public function sayHello()
    {
        return "Hello" . (new Audience)->toWorld();
    }
}

Note we did not have to use the FQN of the Audience class nor add the use App\Audience statement, since both the Greeting and Audience classes are in the same namespace.

Run the bootstrap file again:

php index.php

We should see the output:

HelloWorldHelloWorld

Using the Audience class from index.php

If we wanted to use the Audience class directly from our index.php file, it would be no different than how we used the Greeting class.

<?php

require_once __DIR__ . "/vendor/autoload.php";

use App\Greeting;
use App\Audience;

echo (new Greeting)->sayHello();
echo (new Audience)->toWorld();

Moving the Audience class to a different namespace

Create a new Helpers subdirectory under the app directory:

mkdir -p app/Helpers

Note that the first letter of the subdirectory name Helpers must be uppercase.

Delete the app/Audience.php file and instead re-create it in the app/Helpers directory:

rm app/Audience.php
touch app/Helpers/Audience.php

Add the following to app/Helpers/Audience.php file:

<?php
namespace App\Helpers;

class Audience
{
   public function toWorld()
   {
       return "World";
   }
}

The only difference from before is that the namespace declaration has changed to App\Helpers.

With autoloading, the path of the namespace declaration in the class file, starts with the root namespace App which is mapped to the root app directory, and follows the path of the class file directory.

So since Greeting.php is in the root app directory, the namespace declaration in the file is App and since Audience.php is in the app/Helpers directory, the namespace declaration in the file is App\Helpers.

In order for the casing of the directory names in the directory path and the namespace path declarations to match, the first letter of the subdirectory name of all subdirectories under the root directory app must be uppercase.

Using the modified Audience class from the Greeting class

To use the new Audience class from the Greeting class, modify the app/Greeting.php file:

<?php

namespace App;

use App\Helpers\Audience;

class Greeting
{
    public function sayHello()
    {
        return "Hello" . (new Audience)->toWorld();
    }
}

Since the Audience class is now in different namespace, we added the use App\Helpers\Audience statement to be able to reference it from the Greeting class.

Using the modified Audience class from index.php

To use the modified Audience class directly from the index.php file, all we need to do is to use the new namespace of the Audience class:

<?php

require_once __DIR__ . "/vendor/autoload.php";

use App\Greeting;
use App\Helpers\Audience;

echo (new Greeting)->sayHello();
echo (new Audience)->toWorld();

Moving the index.php file to a subdirectory

Web applications usually bootstrap using an index.php file that is in a subdirectory named public of the root application directory.

So we will move our index.php file into a subdirectory named public to see how we can use autoloading when it is in a subdirectory.

First create a subdirectory named public in the project root directory.

mkdir public

Delete the index.php file then create a new one inside the public directory:

rm index.php
touch public/index.php

Add the following to the public/index.php bootstrap file:

<?php

require_once __DIR__ . "/../vendor/autoload.php";

use App\Greeting;
use App\Helpers\Audience;

echo (new Greeting)->sayHello();
echo (new Audience)->toWorld();

Note that the only thing that changed is the path to the autoload.php file.

Since the index.php file is in a subdirectory, we have to traverse to the parent directory before going down the composer generated vendor directory path.

To run the index.php file we now have to use the subdirectory path:

php public/index.php

A more robust index.php file

Modify the public/index.php file to the following:

<?php

declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

ini_set('display_errors', '1');

//Default setting for php 8+
ini_set('display_startup_errors', '1');

//Default setting for php 8+
error_reporting(E_ALL);

use App\Greeting;
use App\Helpers\Audience;

try {
    echo (new Greeting)->sayHello();
    echo (new Audience)->toWorld();
} catch (Exception $e) {
    echo $e->getMessage();
}

The new code configures some php.ini file settings and adds some error handling.

There can be more than one root namespace

Generally most php applications or composer packages have one root autoloading directory and hence one root namespace.

However you can have multiple root autoloading directories using composer.json.

In addition, a root namespace can be mapped to a root directory that is a subdirectory.

The example below illustrates this.

Add a new root data/db directory that is a subdirectory:

mkdir -p data/db

Map a new root namespace to the subdirectory:

{
  "autoload": {
    "psr-4": {
      "App\\": "app/",
      "Database\\": "data/db/"
    }
  }
}

We have added an additional root namespace named Database in the example. This namespace is mapped to the root directory data/db that is a subdirectory.

The root namespace App maps to the app directory and the root namespace Database maps to the data/db directory.

With this new autoload configuration, the namespace App\Helpers maps to the app/Helpers directory and the namespace Database\Migrations for example maps to a data/db/Migrations directory.

Whenever we add a new namespace mapping to composer.json we must run composer dump-autoload again to update the vendor/autoload.php file.

composer dump-autoload -o

Conclusion

We created the most basic php example to teach the concept of PSR-4 autoloading using composer and the related concept of namespaces.

Using the namespace of a class, you can reference that class from any other class in any other namespace or you can reference it from the index.php bootstrap file.

Also classes from any package used by your application are referenced using namespaces that are autoloaded by the package.

A php or Laravel package autoloads the classes of the package using the autoload mapping in the composer.json file of the package.

When a package is required in our application, all its autoloaded classes will be available to the application.

That is the power of composer autoloading.

With this basic understanding, you can read and understand any php code or create your own autoloaded classes.