--apcu-autoloader必须与--optimize-autoloader联用才有效,因前者仅缓存类名到路径的映射表,后者生成该映射表(autoload_classmap.php);单独使用时无实质内容可缓存,命中率低、无性能提升。

--apcu-autoloader 本身不加速类加载,它只加速“类名 → 文件路径”的映射查找过程;真正提速的是 --optimize-autoloader 生成的 classmap,APCu 只是把这张表缓存进共享内存。
为什么 --apcu-autoloader 单独用无效
这个参数必须和 --optimize-autoloader(或 -o)一起使用,否则 Composer 不会生成可缓存的 classmap 结构。单独加 --apcu-autoloader 时,autoload 仍走 PSR-4 动态匹配逻辑,APCu 缓存的只是零散的查找结果,命中率低、收益微乎其微。
-
composer install --apcu-autoloader:没开--optimize-autoloader,APCu 无实质内容可存,apcu_fetch('composer:autoload')返回false -
composer install --optimize-autoloader --apcu-autoloader:生成autoload_classmap.php并写入 APCu,后续请求跳过文件读取和数组解析 - 验证是否生效:运行
php -r "var_dump(apcu_fetch('composer:autoload'));",非false即为命中
APCu 缓存只在 PHP-FPM 下稳定生效
CLI 模式下 composer dump-autoload --apcu-autoloader 能写入缓存,但 PHP-FPM worker 进程启动后无法复用 CLI 写入的内容——除非你设了 apc.enable_cli=1 且 FPM 和 CLI 共享同一 APCu 实例(通常不推荐)。
- FPM 场景:缓存由首个请求写入,后续 worker 直接读取,效果明显
- CLI 场景(如
php artisan):每次新进程都重新写一次,无共享优势,甚至因写缓存多出毫秒级开销 - Docker 环境常见坑:
apc.enable_cli=0是默认值,FPM 容器需显式配置apc.enable_cli=1才能让composer install正常写入
缓存不更新 = 类找不到的最常见原因
APCu 缓存没有 TTL 或自动失效机制。一旦 vendor 更新、类移动或重命名,旧映射仍留在内存里,class_exists('OldClass') 可能返回 true,但实际加载的是已删除文件路径。
- 部署后必做:
composer dump-autoload --optimize-autoloader --apcu-autoloader,强制刷新 APCu 中的映射 - 多应用共用 APCu 时,必须设置
apcu.namespace(如"apcu.namespace": "myapp-v2"),否则 A 应用的缓存可能覆盖 B 应用的 - 调试技巧:用
apcu_cache_info()['cache_list']查看缓存键是否存在、大小是否合理(几百 KB 正常,超 5 MB 可能混入其他数据)
它不缓存类文件内容,也不加速 files 类型加载
--apcu-autoloader 只作用于类名到路径的映射层(即 autoload_classmap.php、autoload_psr4.php 解析结果),对以下场景完全无效:
-
"files": ["app/Helpers/functions.php"]类型的全局函数加载:每次请求仍 require 一次,不受 APCu 影响 - 类文件本身的解析和执行:靠 OPcache 缓存 opcode,不是 APCu 的事
- 运行时动态生成的类(如 Laravel 的代理类、事件监听器闭包):不在 classmap 中,fallback 查找结果虽可被 APCu 缓存,但首次查找仍要走文件系统
真正关键的不是加不加 --apcu-autoloader,而是确保 autoload_classmap.php 本身足够小、足够准——如果 classmap 里塞了测试类或 dev 包,APCu 缓存再快也救不了内存和查找效率。先砍掉 --no-dev,再确认 "classmap-authoritative": true 是否适用,最后才让 APCu 把这张干净的表“钉”进内存。











