PHP中的函数式还是面向对象编程:如何选择而不迷失方向

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

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

开始课程

引言:两大阵营,一场对决

\n\n

每位PHP开发者迟早都会面临一个选择:采用函数式风格编写代码,还是深入类与对象的海洋?这就像在瑞士军刀和多功能工具之间做选择——两种工具都能解决问题,但方式不同。在本文中,我们将分析PHP中的函数式与面向对象方法,查看真实代码,并决定何时使用哪种工具。

\n\n

PHP是一种独特的语言。它最初是过程式的,后来发展出面向对象特性,而在最新版本(7.4+、8.x)中,它积极吸收了函数式特性:箭头函数、闭包、类型声明。这意味着您可以混合使用不同的编程范式。但如何避免混乱?让我们一起来探讨。

\n\n

基础:两个世界的区别

\n\n

函数式编程(Functional Programming)

\n\n

这里的主角是函数。纯函数没有副作用,始终返回可预测的结果。没有共享状态,没有变量突变。数据像流水线一样按链式传递。

\n\n
// 函数式风格:简单、可预测\n$numbers = [1, 2, 3, 4, 5];\n\n$result = array_map(\n    fn($n) => $n * 2,\n    array_filter($numbers, fn($n) => $n % 2 === 0)\n);\n\nprint_r($result); // [4, 8]
\n\n

注意到了吗?我们没有修改原始数组,也没有使用循环。一切都是声明式的:取出偶数,加倍,返回。这节省了调试时间——因为没有副作用。

\n\n

面向对象编程(OOP)

\n\n

面向对象编程围绕对象构建——这些实体存储状态和行为。类封装数据,子类扩展功能,多态性允许动态改变逻辑。

\n\n
// 面向对象风格:结构化和可复用\nclass NumberProcessor {\n    private array $numbers;\n\n    public function __construct(array $numbers) {\n        $this->numbers = $numbers;\n    }\n\n    public function getEvens(): array {\n        return array_filter($this->numbers, fn($n) => $n % 2 === 0);\n    }\n\n    public function multiplyBy(int $factor): self {\n        $this->numbers = array_map(fn($n) => $n * $factor, $this->numbers);\n        return $this;\n    }\n\n    public function getResult(): array {\n        return $this->numbers;\n    }\n}\n\n$processor = new NumberProcessor([1, 2, 3, 4, 5]);\n$result = $processor->getEvens()->multiplyBy(2)->getResult();\nprint_r($result); // [4, 8]
\n\n

这里我们创建了一个存储状态的对象。可以链式调用方法。优点:如果需要添加新操作,只需在类中增加方法即可。

\n\n

何时函数式编程更胜一筹

\n\n

1. 无副作用的数处理

\n\n

假设您正在编写日志解析器或货币转换器。数据像流水线一样流动:读取 → 过滤 → 转换 → 保存。函数在这里是理想选择。它们不依赖外部状态,易于测试。

\n\n

2. 集合与数组

\n\n

PHP提供了强大的数组处理函数:array_map、array_filter、array_reduce。结合箭头函数(PHP 7.4+),代码变得如诗般优雅。

\n\n
$users = [\n    ['name' => '安娜', 'age' => 25],\n    ['name' => '鲍里斯', 'age' => 17],\n    ['name' => '维卡', 'age' => 30],\n];\n\n$adultNames = array_map(\n    fn($user) => $user['name'],\n    array_filter($users, fn($user) => $user['age'] >= 18)\n);\n\n// ['安娜', '维卡']
\n\n

简洁、可读,无需类。对于简单的数据转换,这是最佳选择。

\n\n

3. 无需模拟(Mock)的测试

\n\n

函数没有状态,因此易于测试。无需创建复杂的模拟对象和桩。只需传入数据,即可获得结果。

\n\n

何时面向对象编程不可或缺

\n\n

1. 带有状态的复杂业务逻辑

\n\n

博客

书籍推荐