PHP遗留代码重构:分步指南

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

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

开始课程

引言:为什么遗留代码重构不是奢侈品,而是必需品



每位PHP开发者迟早都会遇到遗留代码。这可能是一个10年前用PHP 5.3编写的项目,或者是一个“勉强能运行”但每次修改都令人痛苦的应用程序。重构这类代码不仅仅是“梳理”风格,而是一个至关重要的过程,它能提高应用程序的可维护性、性能和安全性。



在本文中,我们将使用现代语言特性(PHP 7.4–8.3)和经过验证的模式,探讨重构遗留PHP代码的实用方法。您将学习如何在不破坏现有系统的情况下安全地进行更改。



1. 评估并记录当前状态



第一步也是最重要的一步——了解您正在处理的内容。不要盲目尝试重构。



1.1. 创建依赖关系图

使用诸如PhpMetrics或Deptrac之类的工具来可视化类之间的关联。这有助于识别“上帝对象”(god objects)和循环依赖。



// 遗留代码中典型“上帝”类的示例class UserManager {    public function save($data) {        // 200行代码:验证、发送邮件、日志记录、数据库操作    }        public function sendNewsletter() {        // 还有150行    }        public function generateReport() {        // 还有100行    }}


1.2. 编写特征测试

在更改代码之前,请确保当前行为已通过测试记录。使用“Golden Master”(快照测试)方法:



// 记录当前行为的测试public function testLegacyCalculation(): void{    $calculator = new OldCalculator();    $result = $calculator->compute(10, 20);        // 如果没有规范,只需保存结果    $this->assertSame(30, $result);}


建议: 如果项目完全没有测试,请从关键业务操作的集成测试开始。使用PHPUnit配合vfsStream来隔离文件系统。



2. 逐步改进:从全局函数到面向对象编程



大部分遗留PHP代码由全局函数和过程式风格组成。逐步迁移到面向对象编程是重构的关键阶段。



2.1. 封装全局函数

将全局函数替换为类的静态方法,然后替换为完整的服务。



// 之前:全局函数function send_email($to, $subject, $message) {    mail($to, $subject, $message);}

// 之后:服务类class MailService { public function __construct( private MailerInterface $mailer ) {} public function send(string $to, string $subject, string $message): bool { return $this->mailer->send($to, $subject, $message); }}


2.2. 摆脱全局变量

全局变量(直接使用$GLOBALS、$_SESSION)是错误的主要来源。使用Registry模式或依赖注入(DI)。



// 糟糕:直接操作全局变量function getCurrentUser() {    global $db;    $id = $_SESSION['user_id'];    return $db->query("SELECT * FROM users WHERE id = $id");}

// 良好:显式依赖注入class UserProvider { public function __construct( private PDO $db, private SessionInterface $session ) {} public function getCurrentUser(): ?User { $id = $this->session->get('user_id'); return $this->db->query('SELECT * FROM users WHERE id = ?', [$id]); }}


3. 安全替换过时结构



PHP在不断发展,许多旧结构已变得不安全且

博客

书籍推荐