Composer 2.0+ 完全移除 PSR-0 支持,psr-0 字段被静默忽略;推荐用 classmap 替代,或仅在必须时通过 spl_autoload_register() 手动实现兼容。

Composer 2.0+ 已彻底不支持 PSR-0 自动加载
直接说结论:composer install 或 composer dump-autoload 在 Composer 2.0 及以上版本中,**完全忽略 "psr-0" 字段**,也不会生成任何 PSR-0 映射逻辑。这不是配置没生效,而是代码层已移除——你写进 composer.json 的 "psr-0" 块,连警告都不会报,只会静默跳过。
典型现象是:类文件明明在 vendor/mylib/class_name.php,命名也符合 MyLib_ClassName → mylib/class_name.php 规则,但运行时仍抛出 Class 'MyLib_ClassName' not found。根本原因不是路径错、大小写错,而是 autoload 根本没注册这条规则。
- 降级 Composer 到 1.x 是最不可取的方案——放弃所有安全更新和新特性,且与现代生态(如 PHP 8.3+、Laravel 11)冲突
- 所谓“开启兼容开关”或插件补丁,官方从未提供,社区方案多已失效或引入严重安全隐患
- 别在
autoload-dev里试psr-0,它同样被忽略
手动注册 PSR-0 加载器(仅限必须运行旧库的场景)
如果你手头有个甩不掉的 PSR-0 类库(比如 pear/console_table 或 Swiftmailer v5.x),又不能改源码,唯一可行路径是在 PHP 运行时用 spl_autoload_register() 补一条加载逻辑——但它必须严格实现 PSR-0 转换规则,不能简单 require_once 硬路径。
关键点:
- 只处理含下划线的类名(
strpos($class, '_') !== false),避免干扰已有 PSR-4 类 - 必须检查
class_exists($class, false)和interface_exists(...),防止重复加载 - 下划线转斜杠要递归拆解前缀,比如
MyOrg_Package_Foo_Bar→myorg/package/foo/bar.php,不是只切最后一段 - 文件路径拼接后,务必用
is_file()判断存在性,否则报Warning: Failed opening required
示例(放在 index.php 或 bootstrap.php 中,且必须在 require_once 'vendor/autoload.php' 之后):
require_once __DIR__ . '/vendor/autoload.php';
spl_autoload_register(function ($class) {
if (false === strpos($class, '_')
|| class_exists($class, false)
|| interface_exists($class, false)) {
return;
}
$parts = explode('_', $class);
$file = strtolower(implode('/', $parts)) . '.php';
$path = __DIR__ . '/vendor/myorg/package/lib/' . $file;
if (is_file($path)) {
require_once $path;
}
});
更推荐:用 classmap 替代 PSR-0(尤其类数少、结构固定)
对绝大多数遗留场景,classmap 比手写 autoload 更可靠、更易维护。它不依赖命名规则,只靠扫描物理文件生成静态映射表,加载速度还比 PSR-4 快。
适用场景:
- 旧类库只有 3–5 个类,文件名和类名不一致(如
DB_MySQL.php里定义了MySQLDB类) - 类库无命名空间,甚至混用
include和class定义 - 你有权限把类文件统一挪到某个目录(如
vendor/mylib/src/)
配置方式(composer.json):
{
"autoload": {
"classmap": ["vendor/mylib/src/"]
}
}
然后执行:composer dump-autoload —— 映射会写入 vendor/composer/autoload_classmap.php,后续新增类必须重跑该命令。
为什么不要碰 files 加载类?
files 字段只适合加载纯函数、常量或初始化脚本(如 helpers.php),**绝不能用来加载类定义文件**。
原因很实际:
- 它会在每次请求时无条件
require_once所列文件,不管是否用到其中的类 - 如果多个
files里定义了同名类,PHP 直接报Fatal error: Cannot redeclare class - 它不参与类查找流程,和自动加载机制无关——类找不到时,
files不会帮你“兜底”
所以,哪怕你看到某个老项目用 "files": ["legacy/class.php"] 加载类,也请立刻迁移到 classmap。这不是风格问题,是避免上线后随机崩溃的底线。
真正容易被忽略的是:PSR-0 的消亡不是“兼容性问题”,而是标准演进的结果;手动补加载器只是临时止血,classmap 才是面向生产环境的务实解法。别在 autoload 配置里留着注释掉的 psr-0 块,Composer 会警告,而且徒增认知负担。










