PHP代码评审清单:常见问题与改进建议
代码评审是团队协作中既考验技术功底又考验沟通能力的事。对 PHP 项目来说,由于语言本身灵活、历史包袱多,评审时更容易陷入“改风格”和“找 bug”的拉锯战。我结合日常评审经验,整理了一份面向 PHP 的实用清单,重点放在那些反复出现、影响可维护性和运行效率的问题上。
类型声明:别让弱类型成为借口
PHP 7 之后类型系统大幅增强,但很多老代码仍在使用 PHPDoc 注释“假装”有类型。评审时首先看函数签名:参数、返回值是否声明了标量类型和类类型?数组是否用 `array` 声明?能用 `int` 就不要写 `@param int $id` 注释。
更值得关注的是联合类型和 `mixed` 的滥用。比如 `function findUser($id): ?User` 比 `function findUser($id): User` 更容易被误用——返回 `null` 的语义必须清晰,否则调用方容易忘记判空。遇到 `mixed` 更要警惕,它等于把类型检查全部推给了运行时,代码评审时应当要求补充类型收窄逻辑或拆分函数。
错误处理:空捕获比报错更可怕
`try { ... } catch (\Exception $e) { }` 是很多遗留代码的“标准操作”。空捕获吞掉异常,等于让线上问题彻底消失。评审时要问:这个异常为什么被捕获?捕获后是记录日志、重试还是转换异常?如果什么都不做,不如不捕获。
另一种常见问题是捕获范围过大。例如用 `catch (\Throwable $e)` 接住了所有错误,包括 `TypeError`、`ParseError`,导致程序在严重故障后继续运行在未知状态。建议只捕获预期可能发生的异常,将非预期错误交给全局处理器。
数据库查询:N + 1 问题永远排第一
循环里查数据库是最典型的性能杀手:
foreach ($orders as $order) {
$user = $db->query('SELECT * FROM users WHERE id = ' . $order['user_id']);
}
评审时如果看到类似结构,第一反应是建议使用 `IN` 查询或关联查询一次性取出数据。Laravel 中利用 `with()` 预加载,原生 SQL 则用 `WHERE id IN (...)`。
另外特别留意 SQL 拼接。哪怕是内部系统,也应使用预处理语句或查询构造器。参数化查询不是可选项,而是底线。
依赖注入:别再用 `new` 打天下
控制器或服务类里直接 `new AnotherService()` 会让测试变得困难,也让类之间的耦合度悄悄上升。评审时看到这种写法,建议改为构造函数注入或至少使用容器解析。如果项目没引入容器,也要用静态工厂或门面模式收拢依赖创建逻辑。
反过来也要防止“注入过多”。一个构造函数有七八个参数,通常意味着这个类违背了单一职责原则。可以考虑按业务动作拆分为多个服务,或者使用参数对象(DTO)合并相关依赖。
资源释放与内存管理
PHP 请求结束后会释放所有资源,但长驻进程(如 Swoole、Worker)或大循环中,资源泄漏会真实存在。文件句柄、流连接、临时目录都要记得释放和清理。评审时注意 `fopen` 后是否有 `fclose`,PDO 长连接是否在异常时正确回滚。
处理超大批量数据时,建议分批处理并 `unset` 释放内存,避免数组无限增长。
注释与命名:代码即文档
评审时最怕看到这样的注释:
// 用户id
$uid = $_GET['uid'];
变量名 `uid` 没有比注释提供更多信息,而注释反而可能过期。建议先改名为 `$userId`,再考虑是否还需要注释。同理,函数名应该表达“做什么”,而不是“怎么做”。如果函数内部超过 30 行,就考虑抽取子函数,用名字解释逻辑块。
“魔术数字”和“魔术字符串”也要在评审中指出。比如 `if ($status == 2)`,至少定义为常量 `STATUS_ACTIVE = 2`,有枚举类更好。
安全细节:输入过滤与输出转义
PHP 老项目容易被塞入各种全局转义逻辑,但在现代框架下,更合理的做法是:输入验证(校验格式、长度、范围),输出时按上下文转义(HTML 用 `htmlspecialchars`,JSON 用 `json_encode`,SQL 用绑定参数)。评审时注意检查是否有直接输出 `$_POST` 或 `$_GET` 数据到页面的地方。文件上传功能要核对后缀名、MIME 类型和存储路径,防止恶意脚本被解析执行。
测试意识:可测性设计
评审不是只看代码能否运行,还要问“这代码怎么测”。如果函数依赖全局状态、静态调用或真实数据库,那测试就难以编写。建议在可能的情况下,将纯逻辑与副作用分离,比如把查询构建与执行分开,把计算逻辑与 I/O 分开。看到一个事务脚本式的方法,可以礼貌地建议“是否可以把核心算法提取成纯函数,方便单元测试?”
代码评审不是找茬,而是帮助团队建立共同的技术语言。这份清单里的每一条背后,都是曾经线上事故或低效维护换来的教训。下次做 PHP 评审时,不妨从上到下过一遍这些点,你会发现不少隐藏的问题慢慢浮出水面。欢迎在评论区分享你在评审中遇到的最典型问题。
年卡会员