PHP遗留代码重构:从A到Z——完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

PHP遗留代码重构:从A到Z



处理遗留代码是每个PHP开发者生活中不可避免的一部分。迟早你会遇到一个用PHP 5.6(甚至4)编写的项目,没有自动加载,使用全局变量,业务逻辑与HTML混杂在一起。重构这样的代码不仅仅是“梳理”,而是一个战略性的过程,可以拯救项目免于技术债务,使其变得可维护。



在本文中,我们将探讨如何系统地进行PHP遗留代码重构,不破坏现有功能,并将“泥潭”转变为现代、可测试的代码。



1. 诊断与评估:从何开始?



在修改代码之前,需要了解你面对的是什么。从项目审计开始。



步骤1. 确定“痛点”

  • 依赖项:是否使用了过时的库?例如,使用mysql_*函数而不是PDO或MySQLi。
  • 架构:是否有任何结构(MVC)?还是所有代码都在一个index.php文件中?
  • 测试:是否存在自动化测试?如果没有,这是你的首要任务。


步骤2. 分析工具

使用静态分析器快速识别问题区域:

  • PHPStan / Psalm:发现类型错误和签名不匹配。
  • Rector:自动将语法更新到新的PHP版本。
  • PhpMetrics:显示代码的圈复杂度和耦合度。


运行Rector从PHP 7.4更新到8.0的示例:

vendor/bin/rector process src/ --set php80


2. “无痛手术”策略:逐步计划



重构遗留代码不是“大爆炸”。它是一系列小而安全的步骤。使用“绞杀藤”技术——逐步用新模块替换旧模块,而不是一次性重写所有内容。



步骤1. 用测试覆盖代码

没有测试,重构就像玩俄罗斯轮盘赌。从特征测试开始:

class LegacyCalculatorTest extends TestCase {    public function testOldCalculation(): void {        // 运行旧代码并记录结果        $result = legacy_calculation(10, 5);        $this->assertEquals(15, $result);    }}

这将在修改前创建一张“安全网”。



步骤2. 隔离“脏”逻辑

如果代码使用全局变量($GLOBALS),将它们提取为函数参数:

// 之前(全局依赖)function processOrder() {    global $db;    $result = $db->query("SELECT * FROM orders");}

// 之后(依赖注入)function processOrder(PDO $db) { $result = $db->query("SELECT * FROM orders");}


步骤3. 替换过时函数

例如,将mysql_*替换为PDO:

// 旧代码$link = mysql_connect('localhost', 'user', 'pass');mysql_select_db('test', $link);$result = mysql_query("SELECT * FROM users", $link);

// 新代码(PDO)$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');$stmt = $pdo->query("SELECT * FROM users");$result = $stmt->fetchAll(PDO::FETCH_ASSOC);


3. 遗留PHP的典型问题及其解决方案



问题1:“意大利面条式代码”(逻辑与表示层混合)

解决方案:将代码分层。将业务逻辑提取到单独的类中,将HTML放入模板(例如,使用Twig)。

// 不好:逻辑和HTML在同一个文件中if ($user->isAdmin()) {    echo "<h1>你好,管理员!</h1>";} else {    echo "<h1>你好,用户!</h1>";}

// 好:控制器 + 模板//

博客

书籍推荐