深入PHP函数式编程:探秘Transducers
你可能听说过函数式编程和高阶函数,但你了解Transducers吗?本文将带你探索这个强大的数据转换工具。
核心要点:
Transducers定义
要理解Transducers,首先需要了解约简器(Reducers)。引用Rich Hickey的话:
一个约简函数正是你传递给
reduce
的函数类型——它接收迄今为止的结果和一个新的输入,并返回下一个迄今为止的结果。
一个Transducer是一个函数,它接收一个约简函数并返回另一个约简函数。
Transducers最初由Rich Hickey引入Clojure,并由Michael Dowling移植到PHP。Transducers是构建可在多种情况下重用的算法转换的强大方法。本文将通过一系列实际示例来探讨其用途。
示例
在继续之前,我们需要通过Composer安装Transducers包。
composer require mtdowling/transducers
我们将为以下示例使用一个简单的User类。
class User { public $id; public $name; public $age; public function __construct($id, $name, $age) { $this->id = $id; $this->name = $name; $this->age = $age; } public function __toString() { return sprintf("\n%d - %s - %d", $this->id, $this->name, $this->age); } } // 示例数据 $data = [ new User(1, "younes", 24), new User(2, "youssef", 26), new User(3, "hamza", 25), new User(4, "ismail", 17), ];
use Transducers as t; $uppercase = t\map(function($user) { return new User($user->id, ucfirst($user->name), $user->age); }); $result = t\xform($data, $uppercase); var_dump($result);
map
函数类似于PHP的array_map
函数:我们传递一个可调用函数,在本例中,它将把用户名首字母大写。
我们使用xform
函数应用我们的uppercase
Transducer。它将我们的数据作为第一个参数,Transducer作为第二个参数。
// 输出 array(4) { [0]=> object(User)#14 (3) { ["id"]=> int(1) ["name"]=> string(6) "Younes" ["age"]=> int(24) } [1]=> object(User)#15 (3) { ["id"]=> int(2) ["name"]=> string(7) "Youssef" ["age"]=> int(26) } [2]=> object(User)#16 (3) { ["id"]=> int(3) ["name"]=> string(5) "Hamza" ["age"]=> int(25) } [3]=> object(User)#17 (3) { ["id"]=> int(4) ["name"]=> string(6) "Ismail" ["age"]=> int(17) } }
xform
返回与数据参数相同类型的值(在本例中为数组)。如果严格需要输出数组,我们也可以使用to_array
。
// ... $result = t\to_array($data, $uppercase); // ...
我们也可以使用to_string
将输出转换为字符串,或者使用into($target, $coll, callable $xf)
将输出转换为特定类型。更多细节请查看文档。
composer require mtdowling/transducers
class User { public $id; public $name; public $age; public function __construct($id, $name, $age) { $this->id = $id; $this->name = $name; $this->age = $age; } public function __toString() { return sprintf("\n%d - %s - %d", $this->id, $this->name, $this->age); } } // 示例数据 $data = [ new User(1, "younes", 24), new User(2, "youssef", 26), new User(3, "hamza", 25), new User(4, "ismail", 17), ];
Transducers最棒的部分是我们可以将多个转换组合成一个Transducer。例如,让我们将用户名的首字母大写并删除未成年人。
use Transducers as t; $uppercase = t\map(function($user) { return new User($user->id, ucfirst($user->name), $user->age); }); $result = t\xform($data, $uppercase); var_dump($result);
filter
函数类似于PHP的array_filter
函数。comp
函数从Transducer列表创建一个Transducer,在本例中为uppercase
(使用map
)和removeMinors
(使用filter
)。
// 输出 array(4) { [0]=> object(User)#14 (3) { ["id"]=> int(1) ["name"]=> string(6) "Younes" ["age"]=> int(24) } [1]=> object(User)#15 (3) { ["id"]=> int(2) ["name"]=> string(7) "Youssef" ["age"]=> int(26) } [2]=> object(User)#16 (3) { ["id"]=> int(3) ["name"]=> string(5) "Hamza" ["age"]=> int(25) } [3]=> object(User)#17 (3) { ["id"]=> int(4) ["name"]=> string(6) "Ismail" ["age"]=> int(17) } }
现在我们有一个可重用的Transducer组合,我们可以随时使用它来根据此标准约简数据。查看文档以了解可用约简函数的列表。
创建Transducer
约简函数接收一个值作为参数,并返回一个约简函数数组,该数组必须包含三个元素:
init
:返回Transducer初始值的函数。如果未提供初始值,则仅在第一次调用时调用。result
:result
函数用于根据调用栈构建最终结果。step
:这是你编写约简逻辑的地方——根据你的约简逻辑,你可能调用它零次或多次。如果没有实际代码,这会变得非常混乱,因此让我们以take
Transducer函数为例。它从数据数组顶部获取n个项目。
// ... $result = t\to_array($data, $uppercase); // ...
use Transducers as t; $uppercase = t\map(function($user) { return new User($user->id, ucfirst($user->name), $user->age); }); $result = t\to_string($data, $uppercase); var_dump($result);
以下是take
约简函数的源代码。
// 输出 string(64) " 1 - Younes - 24 2 - Youssef - 26 3 - Hamza - 25 4 - Ismail - 17"
take
函数被多次调用,带有result
和input
参数。每次调用时,它都会递减remaining
变量并测试它是否小于零。在这种情况下,我们返回一个Reduced
对象实例,这表示一个停止点。
我们的Transducer函数示例将从数据中删除空元素。使用前面关于Transducer工作原理的解释,我们可以访问$input
变量,并决定是调用下一个step
回调还是简单地返回值。
$uppercase = t\map(function($user) { return new User($user->id, ucfirst($user->name), $user->age); }); $removeMinors = t\filter(function($user) { return $user->age >= 18; }); $comp = t\comp( $uppercase, $removeMinors ); $result = t\to_string($data, $comp); var_dump($result);
我们可以通过向我们的$data
变量添加一些空项目来测试这一点。
// 输出 string(48) " 1 - Younes - 24 2 - Youssef - 26 3 - Hamza - 25"
// .... $comp = t\comp( $uppercase, $removeMinors, t\take(2) ); $result = t\to_string($data, $comp); var_dump($result);
结论
在本文中,我们了解了函数式编程世界的一个新方面,称为Transducers。我们回顾了Transducers的目的,即使数据转换更容易。我们还回顾了一些示例,以更好地演示Transducers的价值。你现在在你的开发者工具箱中拥有了一个新的工具,或者至少对Transducer的概念有了更好的理解。
如果你对Transducers有任何疑问,可以在下面发表!
PHP中Transducers的常见问题
PHP中的Transducers是一种数据处理技术,允许你创建可组合和可重用的软件组件。它们本质上是接受一个约简器并返回一个新约简器的函数。这个概念借鉴自Clojure和JavaScript,并已适应PHP。Transducers允许你将数据转换过程与实际数据源分离,使你的代码更模块化、更易于维护。
传统的PHP函数通常将获取数据和转换数据的过程结合在一起,这可能导致难以维护和重用的代码。另一方面,Transducers将这两个过程分开。这意味着你可以创建一个以特定方式转换数据的Transducer,然后将其与任何数据源一起使用,使你的代码更灵活、更可重用。
当然,让我们考虑一个简单的示例。假设你有一个数字数组,并且你想将每个数字加1。你可以创建一个执行此操作的Transducer:
composer require mtdowling/transducers
然后,你可以将此Transducer与任何约简函数和数据源一起使用。
Transducers设计用于与任何数据源一起使用。这是因为它们在单个数据项级别运行,而不是在整个数据源级别运行。因此,你可以将Transducer与数组、数据库查询结果、来自网络连接的数据流等一起使用。唯一的要求是你的数据源必须能够与约简函数一起工作。
Transducers提供了许多好处。它们允许你将数据转换过程与实际数据源分离,使你的代码更模块化、更易于维护。它们还允许你创建可重用的软件组件,可用于任何数据源。最后,因为Transducers操作单个数据项,所以在处理大型数据集时,它们可能比传统的PHP函数更高效。
虽然Transducers提供了许多好处,但它们也可能比传统的PHP函数更复杂。这是因为它们涉及函数式编程的概念,这些概念对一些PHP开发人员来说可能不熟悉。但是,一旦你理解了Transducers的工作原理,它们就可以成为编写干净、高效和可重用代码的强大工具。
是的,Transducers可以与任何PHP框架一起使用。它们是一种通用的数据处理技术,不依赖于任何特定的框架特性。但是,一些框架可能提供自己用于处理Transducers的实用程序,这可以使它们更容易使用。
有很多资源可用于学习PHP中的Transducers。你可以从阅读网上的文章和教程开始,例如SitePoint上的文章。还有一些书籍和在线课程更深入地介绍了这个主题。最后,你可以尝试编写自己的Transducers并在你的PHP项目中使用它们。
是的,Transducers的概念起源于Clojure编程语言,此后已被其他几种语言采用,包括JavaScript和PHP。每种语言都以自己的方式实现Transducers,但基本概念是相同的。
是的,你可以将Transducers与PHP内置的数组函数一起使用。但是,请记住,这些函数可能不如使用Transducer高效,尤其是在处理大型数组时。这是因为PHP的数组函数通常会创建新的数组,而Transducer可以在原地转换数据。
以上是PHP中的传感器变得容易的详细内容。更多信息请关注PHP中文网其他相关文章!