PSR规范是团队协作的硬性门槛,而非风格偏好;PSR-4要求命名空间与目录结构严格对应、大小写敏感且需及时更新自动加载缓存,PSR-12强制统一缩进、大括号换行及换行符格式,并要求strict_types声明紧贴文件头。

不学 PSR,团队协作迟早卡在“谁的代码我读不懂”上。这不是风格偏好问题,而是协作成本的硬门槛——命名不一致、自动加载失败、日志调用方式五花八门,新人三天看不懂调用链,老手改个 LoggerInterface 都得翻三份文档。
PSR-4 自动加载失效时,第一反应不是查 Composer,而是看命名空间和路径是否对齐
常见错误现象:Class "AppControllerIndexController" not found,但文件明明存在。根本原因常是命名空间与目录结构没严格对应。
- 命名空间前缀(如
"App\")必须在composer.json的psr-4配置中完整声明,末尾反斜杠不能漏 - 类文件路径必须完全匹配命名空间小写转路径规则:
AppServiceUserService→app/Service/UserService.php,大小写敏感(Linux 环境下直接报错) -
composer dump-autoload -o生成优化加载器后,修改命名空间或移动文件必须重新执行,否则缓存仍指向旧路径
PSR-12 缩进和大括号换行不统一,CI 工具会直接拒绝合并
很多团队把 PSR-12 当“建议”,结果 PR 被 CI 拦住:不是逻辑错,是 if 后少了空格、public function 的左大括号没换行、或用了 Tab 而非 4 个空格。
- PHP 文件必须用 Unix LF 换行符,Windows 编辑器默认 CRLF,Git 提交前需配置
core.autocrlf=input -
declare(strict_types=1)必须紧贴<?php后,中间不能有空行或注释 - 方法参数超过 3 个时,必须每参数一行,且右括号和左大括号在同一行,例如:
public function __construct(UserRepository $users,CacheInterface $cache,LoggerInterface $logger) {
PSR-3 日志接口写死 Monolog,等于主动放弃替换能力
直接 new MonologLogger 或调用 $logger->info() 看似简单,但一旦要切到 Sentry、Laravel Log 或自研日志服务,就得全局搜索替换所有日志调用点。
立即学习“PHP免费学习笔记(深入)”;
- 业务代码里只依赖
PsrLogLoggerInterface,构造函数注入或容器获取,绝不 new 具体实现 - 适配层只写一次:
class MonologAdapter implements LoggerInterface,把log()转给 Monolog 实例 - 测试时可轻松 mock 接口,不用启动真实日志管道,单元测试速度提升明显
最易被忽略的其实是 PSR-7 的不可变性:每次 withHeader() 都返回新实例,原对象不变。很多人顺手链式调用却忘了赋值,结果 header 没生效——这和 PSR 本身无关,但暴露了没真正理解“契约即约束”的本质。



















