PSR-0 已被 Composer 2.0 完全移除,配置无效且静默忽略;classmap 是加载老项目类的唯一可靠方式,PSR-4 仅适用于已改造命名空间且符合规范的部分代码。

PSR-0 已被废弃,composer 从 2.0 起完全不支持它;所谓“用 PSR-0 兼容旧代码”是无效路径,实际能用的只有 classmap 和(有限条件下)伪 PSR-4。
为什么不能用 PSR-0 加载老项目类
Composer 2.x 不解析 psr-0 字段,即使你写进 composer.json,composer dump-autoload 也直接忽略它。官方文档明确标注 PSR-0 “deprecated since Composer 1.0, removed in 2.0”。老项目里常见的 My_Class 命名、MyClass.php 文件但类叫 My_Class、或 lib/DB/MySQL.php 里定义 MySQL 类——这些都不是 PSR-0 能救的,而是根本没机会触发。
现象:composer.json 里写了 "psr-0": {"": "lib/"},运行 composer dump-autoload 后 vendor/composer/autoload_classmap.php 里仍然没有对应类映射。
- Composer 2+ 版本会静默跳过
psr-0配置,不报错也不警告 - PSR-0 本身要求类名与文件路径严格对应(如
My_Class→My/Class.php),老项目几乎都不满足 - PHP 7.4+ 已移除对下划线命名风格的自动加载支持,
__autoload或spl_autoload_register里靠str_replace('_', '/', $class)的逻辑也大概率失效
classmap 是唯一可靠的老代码加载方式
classmap 不依赖命名规范,只做静态扫描:你指哪,它扫哪,找到类就记下来,运行时直查表。这是处理无命名空间、类名/文件名不一致、.inc 文件、单文件多类等场景的唯一选择。
正确配置示例:
{
"autoload": {
"classmap": [
"lib/",
"config.php",
"includes/Zend/",
"legacy/*.inc"
]
}
}
- 路径必须真实存在,
lib/不存在会 warning,但继续生成;部署到 Linux 时大小写必须和实际文件完全一致 -
config.php这种无扩展名或.inc文件必须显式列出,目录形式(如includes/)不会递归扫描.inc - 通配符只支持
*,不支持**或正则;legacy/DB_*.php可以,legacy/**/DB_*.php不行 - 新增类或删了文件后,必须重跑
composer dump-autoload,否则autoload_classmap.php不更新
PSR-4 只能用于已改造命名空间的部分
如果你把老项目里的 models/User.php 改成 namespace AppModel; class User,并确保文件名=类名,那就可以用 PSR-4 映射 "App\Model\": "models/"。但它对原生 class User(无 namespace)完全无效。
常见误操作:
- 在
psr-4下写"": "models/"—— 空前缀不合法,composer validate会报错 - 把
lib/同时加进psr-4和classmap—— 扫描重复、autoload_classmap.php膨胀、dump-autoload变慢,且毫无收益 - 以为 PSR-4 能 fallback 到文件名模糊匹配 —— 它只认精确的
namespace+类名.php,差一个斜杠或大小写就失败
混合加载时最容易被忽略的细节
老项目常有自定义 __autoload 或 spl_autoload_register 函数,它们和 Composer 的加载器共存会冲突:类可能被加载两次,或先被老加载器抛出 Class not found 就终止了,根本轮不到 Composer。
- 入口文件(如
index.php)顶部加require_once 'vendor/autoload.php'前,必须先调用spl_autoload_unregister('__autoload')或注释掉原有加载逻辑 - 别在
config.php或工具函数文件里require autoload—— 容易引发Cannot redeclare class或define()冲突 -
classmap不加载interface和trait(Composer 5.6+ 对 trait 有实验性支持,但线上环境别依赖)
真正卡住人的往往不是怎么配,而是改完 composer.json 忘了 dump-autoload,或者路径写了 Lib/ 但实际是 lib/,Linux 上一跑就报错。


















