重构遗留 PHP 代码:如何变混乱为有序
每位 PHP 开发人员迟早都会遇到遗留代码——一个陈旧、文档不全且通常无法正常运行的项目。与其从头重写所有内容(这既冒险又昂贵),合理的重构可以让您在不中断业务流程的情况下改进代码。在本文中,我们将探讨如何安全地重构遗留 PHP 项目,同时保持其功能完整。
1. 评估与准备:从何处开始重构遗留代码
在接触代码之前,您需要了解其当前状态。跳过这个阶段——您就有可能破坏一切。
- 创建备份——数据库和项目文件的完整转储。
- 进行审计——找到所有入口点、依赖项和"黑匣子"。使用
grep搜索include、require、eval和mysql_*函数。 - 设置环境——启动项目的本地副本(Docker、Vagrant 或 XAMPP)。
- 添加日志记录——
error_log和监控将有助于跟踪变更后的错误。
通过控制台进行简单审计的示例:
# 搜索已弃用的 mysql 函数grep -rn "mysql_query\\|mysql_connect\\|mysql_fetch" /path/to/legacy/project/重要提示:如果项目没有测试——重构就变成了一场俄罗斯轮盘赌。 首先,用测试覆盖关键逻辑(即使是记录在文档中的手动测试场景)。
2. 重构策略:小步走带来大改变
处理遗留代码的最佳策略是逐步改进。不要试图在一个周末内重写整个项目。采用"童子军规则"方法:让代码比你发现它时更整洁。
2.1. 隔离变更
每次变更都应最小化且原子化。例如:先在一个文件中重命名一个变量,然后将重复的代码提取到一个函数中。
<?php// 重构前(遗留代码)$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];$result = mysql_query($sql);
// 重构后:至少做转义处理$id = (int)$_GET['id'];$sql = "SELECT * FROM users WHERE id = $id";$result = mysqli_query($link, $sql);?>2.2. 使用自动化工具
- PHPStan——静态分析,无需运行代码即可发现错误。
- Rector——自动重构(PSR-12、替换已弃用的函数)。
- PHP CodeSniffer——代码风格检查。
- PHPUnit——单元测试。
运行 Rector 来替换 mysql_* 为 mysqli_* 的示例:
vendor/bin/rector process src/ --set mysql-to-mysqli3. PHP 代码的具体重构技术
3.1. 用面向对象编程替换"意大利面条式代码"
遗留代码通常写成一个包含 HTML 和 PHP 混杂的大型文件。将逻辑分离到类和函数中。
<?php// 糟糕:代码混杂$user = getUser($_GET['id']);echo "<h1>您好," . $user['name'] . "</h1>";if ($_POST['action'] === 'save') { saveUser($_POST);}
// 良好:关注点分离class UserController { public function show(int $id): void { $user = $this->userRepository->find($id); $this->render('profile', ['user' => $user]); }}?>3.2. 移除"死"代码
未使用的函数、注释、被注释掉的代码块——所有这些都会制造噪音。毫不留情地删除它们,但通过 git log 检查以确保该代码未在其他地方使用。
// 搜索未使用的函数(需要 PHPStan)vendo