skip to content

A large PHP e-commerce codebase still spends noticeable request time in Composer's autoloader after -o; how do --classmap-authoritative and --apcu-autoloader compare, and what can each break?

level: seniorimportance: should knowfreq 32%

answer

  1. misses still hit the filesystem
  2. -a: not in the map means absent
  3. APCu caches hits and misses
  4. choose one, not both
  5. runtime-generated classes

basics

~20 s

--classmap-authoritative (-a) treats the classmap as complete, so misses return instantly, but classes generated or added after the dump never load. --apcu-autoloader caches every lookup, hit or miss, in APCu, needs the extension and a fresh prefix per deploy. Pick one.

solid answer

~50 s

After `-o`, known classes are array lookups, so leftover autoloader time usually comes from **misses**: `class_exists()` probes in plugin, module or event systems for classes that do not exist, each falling through to PSR-4 filesystem checks. Composer offers two alternatives, and its guide says to choose one. `--classmap-authoritative` (`-a`, implies `-o`) makes the classmap the only source: not in the map means not found, instantly. It breaks anything that creates class files after the dump, such as proxies or compiled templates generated into a PSR-4 directory, which then fail with class-not-found in production only. `--apcu-autoloader` keeps PSR-4 as a fallback but caches every result, found or not, in APCu shared memory; it needs `ext-apcu`, uses APCu memory, keeps finding classes that exist on disk when first looked up, and by default gets a new random prefix on each dump. Measure first: profile the request before and after.

code

bash · 5 lines
bash
# option A: authoritative classmap (implies -o)
composer install --no-dev --classmap-authoritative --no-interaction

# option B: optimized classmap plus APCu for misses
composer install --no-dev -o --apcu-autoloader --no-interaction

go deeper

for a junior

Know that production autoloaders are optimized and that stricter options exist for large applications.

for a middle

Explain why -o still spends time on misses and what -a and --apcu-autoloader each do about it.

for a senior

Profile first, choose -a only when nothing generates classes at runtime, otherwise APCu, and test the optimized build before release.

for a principal

Weigh a small per-request gain against a production-only failure mode, and set the build policy so the choice is made once, deliberately.

## Where the time goes after `-o` With an optimized autoloader, every class Composer saw at dump time is resolved by one array lookup. If a profile still shows noticeable time in `ClassLoader::findFile()` or `file_exists()` calls from it, the cause is almost always **misses**: lookups for classes that are not in the classmap. In a large shop application they come from: - `class_exists()` or `interface_exists()` probes in plugin, theme, payment-module or event systems that test many optional class names; - optional integrations that check for a package that is not installed; - classes generated at runtime, such as proxies, hydrators or compiled templates written to a cache directory. `-o` does not remember misses, so each one falls through to PSR-4 rules and hits the filesystem, on every request. ## Level 2/A: `--classmap-authoritative` - Enabled by `dump-autoload -a`, `install -a` or `update -a`, or `"classmap-authoritative": true` in `config`. - It **implies `-o`**: the full classmap is built. - At runtime, the loader's rule becomes: if a class is not in the classmap, it does not exist. `findFile()` returns `false` immediately, with no filesystem access and no extension needed. **What breaks:** anything that makes a new class file available **after** the dump. Runtime-generated proxies or compiled classes written into a PSR-4 directory, a plugin uploaded through an admin panel, a hotfix that adds a file without rebuilding: all fail with class-not-found, and only in production, because development does not use `-a`. Composer's guide says to enable it with care for exactly this reason. ## Level 2/B: `--apcu-autoloader` - Enabled by `dump-autoload --apcu`, `install --apcu-autoloader`, or `"apcu-autoloader": true` in `config`. - It does **not** build a classmap by itself, so combine it with `-o`. - On each lookup that is not in the classmap, the loader checks **APCu**, PHP's in-memory user cache, which persists across the requests served by the same PHP server. If there is no entry, it runs the PSR-4 search and stores the result, **found or not found**, so the next request answers from memory. **What it costs:** it requires the APCu extension (the loader skips the cache when APCu is not enabled), it uses APCu memory, and a stale cache entry can outlive the code it describes. By default Composer writes a **random prefix** into each generated autoloader, so every dump starts with a clean namespace; a fixed `--apcu-autoloader-prefix` shared across deploys can serve stale answers. What it cannot do is make a class unfindable that exists on disk the first time it is looked up, which is the failure mode of `-a`. ## Side by side | | `-o` only | `-a` (authoritative) | `-o` + `--apcu-autoloader` | |---|---|---|---| | known classes | array lookup | array lookup | array lookup | | misses | filesystem, every time | instant `false` | filesystem once, then APCu | | classes added after dump | found via PSR-4 | **not found** | found, then cached | | needs extension | no | no | APCu | | main risk | none | class-not-found in production | memory use, stale prefix | Composer's documentation states that 2/A and 2/B address the same problem in different ways and should not be combined. ## Choosing for the shop 1. **Measure** with a profiler on a production-like request; confirm the time is autoloader misses and not something else. 2. If the application and its dependencies generate **no class files at runtime**, or generate them before the dump during the build, use `-a`. It is the simplest and needs no extension. 3. If something writes classes at runtime, either move that generation into the build step and then use `-a`, or use `--apcu-autoloader` with `-o`. 4. Keep `-o` as the floor in every case, and make the choice part of the production build command, never a developer machine setting. 5. After switching to `-a`, run the full test suite and a smoke test **against the optimized build**, because that is the only place the failure mode shows.

  • After switching the production build to --classmap-authoritative, one checkout page fails with a class-not-found error that never appears locally. What is the likely cause?
    That page uses a class created after the dump, typically a proxy or compiled class written at runtime into a PSR-4 directory. The authoritative loader never checks the filesystem, so it cannot find it. Generate those classes during the build, before the dump, or switch to `-o` with `--apcu-autoloader`.
  • Why does Composer give the APCu cache a random prefix by default?
    APCu memory outlives a deploy when the PHP processes are not restarted. A new random prefix in each generated autoloader means a fresh dump never reads entries written by the previous release, so a class that moved or was added is not answered from a stale cache. A fixed custom prefix removes that protection.

An authoritative classmap is a guest list at the door: if a name is not on it, the person is turned away, even if they arrived legitimately after the list was printed. The APCu cache is a doorman with a good memory: the first time, he checks the building; after that he remembers both who is inside and who is not.

saying these in an interview costs you the question

  • --classmap-authoritative still checks PSR-4 directories for classes missing from the map
  • --apcu-autoloader builds the optimized classmap automatically
  • Enabling both -a and --apcu-autoloader gives the best of both
  • An authoritative classmap failure would show up in local development first
  • --apcu-autoloader works the same whether or not the APCu extension is loaded