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?
answer
- misses still hit the filesystem
- -a: not in the map means absent
- APCu caches hits and misses
- choose one, not both
- 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 sAfter `-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# 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-interactiongo deeper
Know that production autoloaders are optimized and that stricter options exist for large applications.
Explain why -o still spends time on misses and what -a and --apcu-autoloader each do about it.
Profile first, choose -a only when nothing generates classes at runtime, otherwise APCu, and test the optimized build before release.
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