skip to content

In a composer.json, how do you configure psr-4 autoloading for your own code, and what does requiring vendor/autoload.php give you?

level: juniorimportance: must knowfreq 62%

answer

  1. namespace prefix to directory
  2. prefix ends with two backslashes in JSON
  3. require vendor/autoload.php once
  4. new prefix needs dump-autoload
  5. new class under a prefix does not

basics

~20 s

Map a namespace prefix to a directory under autoload.psr-4, for example "App\": "src/", then require vendor/autoload.php once at the entry point. That file registers Composer's class loader for your code and every dependency, and includes any files entries.

solid answer

~40 s

In `composer.json` you add `"autoload": {"psr-4": {"App\\": "src/"}}`: a namespace **prefix**, ending in a backslash (written `\\` in JSON), mapped to a directory relative to the package root. A prefix can map to several directories as an array, and an empty prefix `""` makes a fallback directory. Composer merges your rules with every installed package's rules into generated files under `vendor/composer/` and writes `vendor/autoload.php`. Requiring that file once, in the front controller or CLI entry script, registers Composer's `ClassLoader`, includes any `files` entries and returns the loader, so `new App\Billing\Invoice()` just works. After **adding or changing a mapping** you run `composer dump-autoload`; after adding a **class** under an existing PSR-4 prefix you do not, because the default loader looks the file up on disk.

code

json · 8 lines
json
{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    },
    "autoload-dev": {
        "psr-4": { "App\\Tests\\": "tests/" }
    }
}

go deeper

for a junior

Know the psr-4 key format, that vendor/autoload.php is required once at the entry point, and when composer dump-autoload is needed.

for a middle

Explain what autoload.php registers and includes, why new PSR-4 classes need no rebuild, and why the trailing separator matters.

for a senior

Keep mappings minimal and case-correct, keep tests in autoload-dev, and catch mapping errors in CI before a case-sensitive server does.

for a principal

Set namespace and directory conventions for a codebase so autoloading stays predictable as teams and packages multiply.

## What Composer's autoloader is PHP loads a class definition the first time code uses a class it has not seen, by calling the autoloaders registered with the engine. **Composer generates one** for you: it reads the `autoload` rules of your project and of every installed package, writes them into PHP files under `vendor/composer/`, and gives you one entry point, `vendor/autoload.php`. How PHP's autoload hook works and how the PSR-4 standard turns a class name into a path are the language's and the standard's business; this question is about Composer's side. ## Configuring `psr-4` ```json { "autoload": { "psr-4": { "App\\": "src/", "App\\Legacy\\": ["lib/", "legacy/"] } } } ``` - The **key** is a namespace prefix. It must end with a namespace separator, written `\\` in JSON because the backslash is JSON's escape character. The trailing separator stops `Foo\` from also matching `FooBar\`. - The **value** is a directory relative to the package root, or an array of directories searched in order. - The prefix is **not** part of the path: `App\Billing\Invoice` under `"App\\": "src/"` lives in `src/Billing/Invoice.php`. - An **empty prefix** `"": "src/"` makes `src/` a fallback for any namespace, rarely a good idea in an application. - Composer also supports the older `psr-0` key; new code uses `psr-4`. All PSR-4 rules from all packages are merged into `vendor/composer/autoload_psr4.php` during `install`, `update` or `dump-autoload`. ## What `vendor/autoload.php` does Including it: 1. runs the runtime platform check first, when one was generated; 2. registers Composer's `ClassLoader` with the PHP engine, loaded with the merged `psr-4`, `classmap` and legacy `psr-0` rules; 3. includes every `files` entry, dependencies first, the root package last; 4. **returns the `ClassLoader` instance**, so a test bootstrap can add rules at runtime with `$loader->addPsr4('App\\Tests\\', __DIR__)`. You require it **once**, as early as possible: in the web front controller (`public/index.php`) and in each CLI entry script. Libraries never include it themselves; the application that installs them does. ## When you must regenerate | Change | `composer dump-autoload` needed? | |---|---| | add a class under an existing PSR-4 prefix | no, found on disk at first use | | add or change a `psr-4` prefix or directory | yes | | add a class in a `classmap` directory | yes | | add a `files` entry | yes | | install, update or remove a package | no, those commands regenerate it | That first row is PSR-4's main convenience, and the reason Composer's documentation recommends it: new classes need no rebuild during development. It is also why an **optimized** production autoloader behaves differently, a separate topic. ## Common mistakes - Writing a single backslash at the end of the JSON key: the backslash escapes the closing quote, the JSON no longer parses, and Composer reports a parse error. - Forgetting the trailing separator, so the key reads `"App": "src/"` instead of `"App\\": "src/"`; Composer rejects it with an error that psr-4 namespaces must end with a namespace separator. - Mismatched case between the namespace and the directory: it works on a case-insensitive filesystem on a laptop and fails on a Linux server. - Adding a new prefix and forgetting `dump-autoload`, then blaming the namespace. - Including `vendor/autoload.php` from many files instead of once at the entry point. ## What the generated files are Looking inside `vendor/composer/` demystifies the whole mechanism. After a dump you will find, among others: - `autoload_psr4.php`: an array from each PSR-4 prefix to its directories, merged across all packages; - `autoload_classmap.php`: an array from class name to file, including Composer's own classes and anything from `classmap` rules; - `autoload_files.php`: the ordered list of `files` entries, when any package declares them; - `autoload_real.php` and `autoload_static.php`: the bootstrap that builds the `ClassLoader` from those arrays; - `ClassLoader.php`: the loader class itself. All of them are generated: never edit them by hand, and never commit `vendor/` to fix an autoload problem. Change `composer.json` and dump again. ## Where test code goes Test namespaces belong in `autoload-dev`, which uses the same syntax but is root-only and left out of `--no-dev` installs, so production's autoloader does not carry test classes.

  • You added src/Billing/Invoice.php under an existing App\ prefix and the class is found without any Composer command. Why?
    With the default, unoptimized autoloader, a PSR-4 rule is resolved at runtime: the loader turns the class name into a path under `src/` and checks whether the file exists. Nothing needs to be regenerated for a new class. You need `composer dump-autoload` only when the mapping itself changes, or when the autoloader was dumped as an authoritative classmap.
  • What does require 'vendor/autoload.php' return, and when is that useful?
    It returns Composer's `ClassLoader` instance. A test bootstrap or a tool can call methods on it such as `addPsr4()` to register extra prefixes at runtime without touching `composer.json`.

saying these in an interview costs you the question

  • You must run composer dump-autoload every time you add a new class under a PSR-4 prefix
  • Every PHP file should require vendor/autoload.php at the top
  • A PSR-4 prefix key without a trailing separator works the same as one with it
  • A library should require its own vendor/autoload.php so it works when installed
  • The namespace prefix is repeated as a directory inside the mapped path