classmap通过静态扫描生成类映射,即执行composer dump-autoload时递归扫描配置路径下所有.php文件,提取其中class/interface/trait声明并硬编码进autoload_classmap.php,不解析命名空间、不执行代码、不支持动态类定义。

Composer classmap 是怎么扫描并生成类映射的?
classmap 不是实时解析 PHP 文件,而是在 composer dump-autoload(或安装/更新时)一次性扫描指定目录下所有 .php 文件,提取其中声明的类、接口、trait 名称,并记录其文件路径。它不依赖命名空间或文件名规则,只认 class XXX、interface XXX、trait XXX 这类语法结构。
常见错误是把类文件放在未配置的目录里,或者文件里用了动态类名(如 class {$name})、条件定义(if (true) { class A {} }),这些都会导致 classmap 漏掉类。
- 扫描路径必须是真实存在的目录,不支持 glob 模式(如
src/**/*.php) - 子目录会递归扫描,但软链接默认跳过(除非加
--optimize-autoloader并启用symlinks选项) - 如果类名拼写错误(比如大小写不一致),classmap 会存错路径,运行时抛出
Class 'xxx' not found - 修改类名或删文件后,必须重新执行
composer dump-autoload,否则缓存仍指向旧位置
files 配置适合加载哪些代码?
files 用于直接载入“非类定义”的 PHP 文件,比如工具函数、全局常量、辅助闭包,或者用 function_exists() 包裹的函数声明——这些内容不会被 classmap 捕获,也不符合 PSR-4 的命名规范。
典型场景:你写了 src/helpers.php,里面全是 function str_slug($s) { ... },想在任何地方直接调用,不用 require。
-
files列表里的每个文件会在 Composer 自动加载器初始化时 无条件 include_once,顺序按配置数组顺序执行 - 不能放类定义文件(哪怕只有一个类),否则可能和 classmap / PSR-4 冲突,造成重复定义错误
Cannot declare class X, because the name is already in use - 文件路径是相对于
composer.json所在目录的,不要写成绝对路径或带./前缀(Composer 会报错) - 修改
files后也需运行composer dump-autoload,否则新文件不会被加载
PSR-4 和 classmap 能共存吗?优先级怎么算?
能共存,而且很常见:用 PSR-4 管理主业务类(结构清晰、开发友好),用 classmap 加速老代码或第三方静态库(避免逐个命名空间配置)。
自动加载器按注册顺序尝试加载:Composer 默认把 PSR-4 映射放在前面,classmap 在后;但实际生效顺序取决于 vendor/autoload.php 中 ClassLoader::setPsr4() 和 ClassLoader::addClassMap() 的调用次序——这个顺序由 composer dump-autoload 生成,不可手动调整。
- 当一个类同时匹配 PSR-4 规则和 classmap 条目时,PSR-4 会先命中并返回路径,classmap 根本不会触发(所以不会报重复定义)
- classmap 更快(纯数组查找),但失去命名空间语义;PSR-4 稍慢(路径拼接 + 文件存在检查),但支持热替换和 IDE 跳转
- 如果某个类在 PSR-4 下找不到文件,自动加载器才会查 classmap;查不到才报错
- 别为了“统一”强行把 PSR-4 项目全挪进 classmap——调试困难、IDE 失效、团队协作成本上升
自己写的类没被加载?三步快速定位
不是 autoload 配置写错,就是路径/命名/执行时机出了问题。别猜,直接验证:
- 运行
composer show -p,确认你的类是否出现在输出中(classmap 类会列在classmap段,PSR-4 类显示为psr-4映射) - 临时加一行
var_dump(class_exists('Your\Full\ClassName'));,看返回false还是true;如果是false,再检查get_declared_classes()里有没有它 - 打开
vendor/composer/autoload_classmap.php(classmap 模式下)或autoload_psr4.php,搜索你的类名,看路径是否正确、文件是否存在、大小写是否一致
最常被忽略的是:类文件保存编码含 BOM、PHP 短标签 未启用、或类定义前有输出(包括空格和 UTF-8 BOM),导致解析失败,classmap 就压根读不到那个 class 关键字。











