PHP代码重构:何时需要以及如何不损害项目

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

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

开始课程

PHP代码重构:何时需要以及如何不损害项目

\n\n

每位PHP开发者迟早都会遇到想要重写的代码。遗留PHP项目充满了“魔法数字”(magic numbers)、长达一屏的函数以及负责所有事情的类。你很想动手整理一番。但值得吗?如果值得——如何安全有效地进行PHP代码重构?

\n\n

在本文中,我们将分析何时确实需要重构,何时最好保持原样。你将看到PHP中糟糕代码和优秀代码的真实示例,获得一份操作检查清单,并了解如何避免将代码改进变成一场灾难。

\n\n

何时PHP代码重构是合理的?

\n\n

重构是在不改变代码外部行为的情况下改变其内部结构。听起来简单,但在实践中这是开发中最危险的活动之一。以下是需要考虑改进PHP代码的迹象:

\n\n
    \n
  • 代码有“坏味道”(code smells)。 长方法、重复代码、上帝类(God objects)、难以理解的变量名。
  • \n
  • 添加新功能变得痛苦。 如果每个拉取请求都会破坏其他三个地方——这是一个警示信号。
  • \n
  • 你在一周后就不理解自己写的方法做了什么。 糟糕的代码是需要为每一行写注释的代码。
  • \n
  • 违反了单一职责原则(SRP)。 一个既创建用户、又发送邮件、还生成报告的UserManager类——是重构的典型候选。
  • \n
\n\n

但有些情况下,PHP代码重构可能会造成损害:

\n
    \n
  • 明天就是截止日期,而代码还能运行。
  • \n
  • 没有测试。没有测试,任何更改都像在玩俄罗斯轮盘赌。
  • \n
  • 代码是临时为原型编写的,而原型明天就会被丢弃。
  • \n
\n\n

安全重构的规则

\n\n

在着手进行PHP代码重构之前,请记住三条铁律:

\n\n
    \n
  1. 用测试覆盖代码。 至少是集成测试。如果没有测试——为关键部分编写测试。
  2. \n
  3. 小步重构。 一次只重构一个方法。推送——检查——继续前进。
  4. \n
  5. 不要混合重构和添加功能。 这是两个不同的任务。在不同的提交中完成它们。
  6. \n
\n\n

PHP代码重构示例:从糟糕到优秀

\n\n

让我们看一些真实示例。假设我们有一个计算折扣的函数。在典型的遗留项目中,它看起来像这样:

\n\n

重构前(糟糕的代码)

\n
function calculateDiscount($user, $order) {\n    $discount = 0;\n    if ($user->isVip()) {\n        $discount = 10;\n        if ($order->getTotal() > 1000) {\n            $discount = 15;\n        }\n    }\n    if (date('Y-m-d') == '2025-12-31') {\n        $discount = $discount + 5;\n    }\n    if ($order->getItemsCount() > 5) {\n        $discount = $discount + 3;\n    }\n    return $discount;\n}
\n\n

问题:魔法日期、数字常量、逻辑混合(用户、订单、日期)。如果明天出现新的促销活动——这个函数会变得更长。

\n\n

PHP重构后(优秀的代码)

\n
class DiscountCalculator {\n    private const NEW_YEAR_DATE = '2025-12-31';\n    \n    public function calculate(User $user, Order $order): int {\n        $discount = $this->getBaseDiscount($user) \n                  + $this->getHolidayBonus() \n                  + $this->getVolumeBonus($order);\n        \n        return min($discount, 50); // 不超过50%\n    }\n    \n    private function getBaseDiscount(User $user): int {\n        if ($user->isVip() && $user->getTotalSpent() > 1000) {\n            return 15;\n        }\n        return $user->isVip() ? 10 : 0;\n    }\n    \n    private function getHolidayBonus(): int {\n        retu                

博客

书籍推荐