# PSR-4 and Autoloading: Escaping the Include Chain

> Moving away from manual class includes to standard autoloading: the difference between PSR-0 and PSR-4, and Composer integration.

- Published: 2014-03-02
- Category: Languages
- Tags: PHP
- Reading time: 4 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/psr-4-and-autoloading-escaping-the-include-chain/
- Language: en-US
- Author: Muhammet Şafak

---
[Last month I wrote about switching to Composer](/en/blog/switching-to-composer-stop-managing-php-dependencies-by-hand). In that post I briefly touched on the `autoload` section. This time I want to go into more detail, because **PSR-4** and autoloading genuinely require a change in habits.

My old habit was to `require_once` every class I needed at the top of each file. As the project grew, so did the list. In some files I had more than ten lines of `require_once` chains.

```php
<?php
require_once 'lib/Database.php';
require_once 'lib/User.php';
require_once 'lib/Auth.php';
require_once 'helpers/Validator.php';
// ... and it keeps going
```

There are several problems with this approach: you have to keep track of where every file lives, a typo in the path throws an error, and if you move a directory you have to update every `require`. On top of that, including the same class in multiple places triggers a PHP warning — `require_once` prevents that, but it bloats the code.

Once I renamed a class and had to manually update the `require_once` path in seven different files that used it. That day I realized this approach simply was not sustainable.

## What is PSR?

**PSR (PHP Standards Recommendation)** is a set of application standards published by PHP-FIG (PHP Framework Interop Group). They establish shared conventions so that PHP libraries and frameworks can interoperate with each other.

Two standards relate to autoloading: **PSR-0** and **PSR-4**. Both define a mapping between a class name and its file path.

## The Difference Between PSR-0 and PSR-4

**PSR-0** appeared in 2009 and treated both the namespace separator `\` and the underscore `_` as directory separators. This made it compatible with older naming systems like `Vendor_Package_ClassName`.

```
Vendor\Package\ClassName → vendor/Package/ClassName.php
Vendor_Package_ClassName → vendor/Package/ClassName.php
```

**PSR-4** was introduced to reduce the complexity PSR-0 brought. It uses only the namespace separator `\` and drops the underscore conversion. The result is cleaner and more predictable:

```
App\Http\Controller → src/Http/Controller.php
```

PSR-4 is the active standard today; PSR-0 is deprecated. Use PSR-4 in new projects.

## Setting Up PSR-4 with Composer

You add an autoload section to `composer.json`:

```json
{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}
```

This means: look for any class starting with `App\` inside the `src/` directory. So the class `App\Http\UserController` maps to `src/Http/UserController.php`.

Then you regenerate the autoload map:

```bash
composer dump-autoload
```

And you add a single line to your project's entry point:

```php
<?php
require 'vendor/autoload.php';

$controller = new App\Http\UserController();
```

The `require_once` chain is gone. PHP now finds the file automatically the moment you use the class.

## Directory Structure

With PSR-4, the directory structure mirrors the namespace structure:

```
src/
├── Http/
│   ├── UserController.php   → App\Http\UserController
│   └── PostController.php   → App\Http\PostController
├── Models/
│   └── User.php             → App\Models\User
└── Services/
    └── Mailer.php           → App\Services\Mailer
```

This layout becomes much easier to manage as the project grows. Adding a new class means simply dropping the file in the right directory — nothing else needs to be updated.

Having the namespace structure reflect the directory structure means you can always predict where things live. When you want to find the `App\Services\Mailer` class, you go straight to `src/Services/Mailer.php`. This also helps anyone joining the project get up to speed quickly.

## Multiple Namespaces

If your project has more than one namespace, you can define them all:

```json
{
    "autoload": {
        "psr-4": {
            "App\\": "src/",
            "Tests\\": "tests/"
        }
    }
}
```

## The Classmap Option

For legacy code that does not follow PSR-0/PSR-4, there is `classmap`. Composer scans the directory you specify and maps every class to its file:

```json
{
    "autoload": {
        "classmap": ["lib/"]
    }
}
```

This is useful for pulling old code that has no naming conventions into the autoloading system. For anything you write from scratch, prefer PSR-4.

The practical difference between `classmap` and PSR-4 is this: `classmap` rescans the directory and produces a static map every time you run `composer dump-autoload`. PSR-4 applies the convention at runtime, so as long as you put the file in the right place, you do not need to run `dump-autoload` at all. That small convenience adds up over the course of a normal development day.

## Conclusion

Adopting PSR-4 and Composer autoloading may look like a small change, but it makes a real difference in day-to-day work. You never have to write a `require` by hand, moving directories hurts a lot less, and your project interoperates cleanly with any other PSR-compliant library. Even if you are not using a framework, embracing this standard keeps your codebase organized.
