绝大多数新项目应选PSR-4,因其按命名空间映射目录、写法清晰、IDE支持好且无需手动dump-autoload;仅老项目无命名空间类或需显式加载的全局函数时才考虑classmap。

psr-4 和 classmap 选哪个
绝大多数新项目直接用 psr-4,它按命名空间映射目录,写法清晰、IDE 支持好、开发时无需额外 dump-autoload。只有两类情况才考虑 classmap:一是老项目里大量无命名空间的类文件(比如 Zend Framework 1 风格),二是某些必须提前注册的全局函数或接口定义文件——但这类文件本身就不该靠 autoload 加载,更推荐显式 require。
常见错误现象:Class not found 却确认文件存在,往往是因为 psr-4 的命名空间前缀没对齐实际目录结构,或者末尾多写了 (如 "App\": "src/App/" 写成 "App\": "src/App\")。
-
psr-4要求命名空间与路径严格对应,AppControllerHome必须在src/Controller/Home.php -
classmap是扫描生成的静态映射,修改文件后必须手动运行composer dump-autoload - 不要混用
psr-4和psr-0,后者已废弃,Composer 2.2+ 不再支持
autoload-dev 怎么配才不污染生产环境
autoload-dev 里的路径只在 composer install --no-dev 之外生效,但很多人误以为它“只加载测试代码”——其实只要进了 vendor/autoload.php,所有 autoload + autoload-dev 的规则都会被合并注册。真正隔离靠的是「不把测试类放进生产代码路径」。
典型踩坑:把 tests/ 目录加进主 psr-4,结果 CI 里跑 phpunit 没问题,但线上部署后 new TestHelper() 竟然能 new 成功,因为 autoloader 已经把它认作合法类。
- 主
autoload只放 src、lib 等生产代码路径 -
autoload-dev专用于tests/、examples/、stubs/这类非交付内容 - 如果测试类需要模拟生产类行为,用
classmap扫描tests/mocks/更安全,避免命名空间冲突
files 类型 autoload 的真实用途
files 是唯一能加载函数、常量、trait 的 autoload 方式,但它不是“自动加载”,而是“每次 require vendor/autoload.php 时无条件 include”。所以它适合放那些必须提前声明、又不能写进类里的东西,比如全局辅助函数或配置常量。
容易被忽略的点:一旦用了 files,这些文件就永远在内存里,哪怕你只用了一个函数。性能影响小,但会破坏“按需加载”的原则,调试时也难追踪来源。
- 只放
function、const、define()、trait,别放class(否则和 psr-4 冲突) - 路径必须是相对于
composer.json的相对路径,不能用../跨出项目根目录 - 多个文件按数组顺序加载,有依赖关系时注意顺序,比如先
functions.php再helpers.php
vendor/autoload.php 被多次 require 会怎样
不会报错,但会重复注册 autoloader,导致 spl_autoload_register 队列变长,轻微拖慢后续类加载。更严重的是,如果某次 require 发生在框架启动之后(比如在中间件里手动 require),可能覆盖掉框架自己的 autoloader 行为。
常见场景:Swoole 或 RoadRunner 这类常驻进程里,第一次请求加载了 vendor/autoload.php,第二次请求又执行一遍——这不是 Composer 的问题,是应用层没控制好入口逻辑。
- 确保整个生命周期只
require_once 'vendor/autoload.php' - 不要在函数或循环里动态 require 它
- CLI 脚本里如果要复用 Web 项目的 autoload,用
include前先检查class_exists('ComposerAutoloadClassLoader')










