Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Separating Classes into Different Files (PSR-4)

Everything in this chapter has been heading toward one small block of JSON. Your classes have namespaces, your files import them with use, src/ mirrors the namespace tree, and still nothing has told Composer that any of this is connected. PSR-4 is the published rule that maps a namespace to a directory on disk. It comes from the PHP-FIG, the group that coordinates conventions like this one across the ecosystem.

The rule, precisely

PSR-4 works on prefixes. You tell Composer: β€œany class whose name starts with this prefix lives under this directory, and the rest of the name is the rest of the path.” In composer.json:

{
    "name": "you/your-project",
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}
The PSR-4 rule applied step by step: App\Models\Product loses its App\ prefix, the backslashes become slashes and .php is added, then src/ is put in front, giving src/Models/Product.php

With that mapping, App\Models\Product resolves in three moves. Strip the App\ prefix: Models\Product. Turn the backslashes into slashes and add .php: Models/Product.php. Put the base directory in front: src/Models/Product.php. That is the entire algorithm. No configuration per class, no list of files to maintain, one rule applied every time.

Warning

Note the double backslash in "App\\". This is a JSON string, so a literal backslash must be escaped. Easy to forget, and Composer will tell you plainly (an autoload path that does not resolve) if you do.

Wiring it up

If you ran composer init in Hello, Composer!, add the autoload block to your existing composer.json by hand. Then tell Composer to act on it:

$ composer dump-autoload
Generating autoload files
Generated autoload files

This regenerates the files in vendor/composer/, including the PSR-4 map you peeked at in Packages and Autoloading. From now on, require 'vendor/autoload.php' finds your own App\ classes exactly the way it already found Termwind.

Try it: run the entry point from the previous section. It prints 74. Then add a new class under src/, use it from the same script, and run again. Nothing else to do.

When to run it again

The PSR-4 autoloader resolves paths by rule, not from a fixed list, so in most setups a new class in the right place is found immediately. Still, running composer dump-autoload after adding classes is a habit worth having. Some deployment setups build an optimized class map (composer dump-autoload --optimize, or automatically with composer install --no-dev on a production server) that trades the on-the-fly rule for speed, and that map only knows the classes that existed when it was generated. If you add src/Models/Discount.php and PHP suddenly cannot find App\Models\Discount, composer dump-autoload is the first thing to try. It costs nothing.

Checking your work

Composer also notices when files and namespaces drift apart: a typo in a namespace line, a class saved in the wrong folder:

$ composer dump-autoload
Generating autoload files
Warning: Ambiguous class resolution, "App\Models\Product" was found in
both "src/Models/Product.php" and "src/Models/product.php", the first
will be used.
Generated autoload files

That is the whole system, and the best part is how little of it you think about day to day. Namespace the class, put the file where the namespace says, and the autoloader (the one line you wrote in Hello, Composer! and have not touched since) finds it. From here on, every multi-file example in this book assumes exactly this setup: a src/ folder, an App\ namespace, and one require that never needs another one added after it.