In-depth PHP functional programming: Exploring Transducers
You may have heard of functional programming and advanced functions, but do you know Transducers? This article will take you to explore this powerful data conversion tool.
Core points:
Transducers definition
To understand Transducers, you first need to understand Reducers. Quoting Rich Hickey:
A reduction function is exactly the type of function you pass to
reduce
- it receives the result so far and a new input and returns the next so far result.
A Transducer is a function that receives one reduction function and returns another reduction function.
Transducers were initially introduced to Clojure by Rich Hickey and ported to PHP by Michael Dowling. Transducers are a powerful way to build algorithmic transformations that can be reused in a variety of situations. This article will explore its use through a series of practical examples.
Example
Before proceeding, we need to install the Transducers package through Composer.
composer require mtdowling/transducers
We will use a simple User class for the following example.
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
function is similar to the array_map
function of PHP: we pass a callable function, which in this case will capitalize the username initial.
We use the xform
function to apply our uppercase
Transducer. It takes our data as the first parameter and the Transducer as the second parameter.
// 输出 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
Returns a value of the same type as the data parameter (in this case an array). If you strictly need to output an array, we can also use to_array
.
// ... $result = t\to_array($data, $uppercase); // ...
We can also use to_string
to convert the output to a string, or use into($target, $coll, callable $xf)
to convert the output to a specific type. For more details, please see the documentation.
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), ];
The best part about Transducers is that we can combine multiple conversions into one Transducer. For example, let's capitalize the initial letter of the username and delete the minor.
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
function is similar to the array_filter
function of PHP. The comp
function creates a Transducer from the Transducer list, in this case uppercase
(using map
) and removeMinors
(using 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) } }
Now we have a reusable Transducer combination that we can use at any time to reduce data based on this standard. Check the documentation for a list of available reduction functions.
Create Transducer
The reduction function receives a value as a parameter and returns an array of reduction functions that must contain three elements:
init
: Function that returns the initial value of Transducer. If no initial value is provided, it is called only on the first call. result
:result
function is used to build the final result from the call stack. step
: This is where you write the reduction logic—you may call it zero or multiple times according to your reduction logic. This gets very confusing without actual code, so let's take the take
Transducer function as an example. It gets n items from the top of the data array.
// ... $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);
The following is the source code of the take
reduction function.
// 输出 string(64) " 1 - Younes - 24 2 - Youssef - 26 3 - Hamza - 25 4 - Ismail - 17"
take
function is called multiple times with result
and input
parameters. Each time it is called, it decrements the remaining
variable and tests whether it is less than zero. In this case, we return a Reduced
object instance, which represents a stop point.
Our Transducer function example will remove empty elements from the data. Using the previous explanation of how Transducer works, we can access the $input
variable and decide whether to call the next step
callback or simply return the value.
$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);
We can test this by adding some empty items to our $data
variable.
// 输出 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);
Conclusion
In this article, we understand a new aspect of the functional programming world called Transducers. We review the purpose of Transducers, even if data conversion is easier. We also reviewed some examples to better demonstrate the value of Transducers. You now have a new tool in your developer toolbox, or at least have a better understanding of the concept of Transducer.
If you have any questions about Transducers, you can post it below!
FAQs about Transducers in PHP
Transducers in PHP is a data processing technology that allows you to create composable and reusable software components. They are essentially functions that accept a reducer and return a new reducer. This concept is borrowed from Clojure and JavaScript and has adapted to PHP. Transducers allow you to separate the data conversion process from the actual data source, making your code more modular and easier to maintain.
Traditional PHP functions usually combine the process of getting and converting data, which can make code difficult to maintain and reuse. Transducers, on the other hand, separate the two processes. This means you can create a Transducer that converts data in a specific way and then use it with any data source to make your code more flexible and reusable.
Of course, let's consider a simple example. Suppose you have an array of numbers and you want to add 1 to each number. You can create a Transducer that does this:
composer require mtdowling/transducers
You can then use this Transducer with any reduction function and data source.
Transducers are designed to be used with any data source. This is because they run at the single data item level, not at the entire data source level. Therefore, you can use Transducer with arrays, database query results, data streams from network connections, etc. The only requirement is that your data source must be able to work with the reduction function.
Transducers offer many benefits. They allow you to separate the data conversion process from the actual data source, making your code more modular and easier to maintain. They also allow you to create reusable software components that can be used in any data source. Finally, because Transducers operate on a single data item, they may be more efficient than traditional PHP functions when dealing with large data sets.
While Transducers provide many benefits, they may also be more complex than traditional PHP functions. This is because they involve the concepts of functional programming that may not be familiar to some PHP developers. But once you understand how Transducers work, they can be a powerful tool for writing clean, efficient and reusable code.
Yes, Transducers can be used with any PHP framework. They are a general data processing technology that does not depend on any specific framework features. However, some frameworks may provide their own utilities for handling Transducers, which can make them easier to use.
There are many resources available to learn Transducers in PHP. You can start by reading online articles and tutorials, such as articles on SitePoint. There are also books and online courses that cover the topic in more depth. Finally, you can try writing your own Transducers and using them in your PHP project.
Yes, the concept of Transducers originated from the Clojure programming language and has since been adopted by several other languages, including JavaScript and PHP. Each language implements Transducers in its own way, but the basic concepts are the same.
Yes, you can use Transducers with PHP's built-in array functions. However, remember that these functions may not be as efficient as using Transducer, especially when dealing with large arrays. This is because PHP's array functions usually create new arrays, and Transducer can convert data in place.
The above is the detailed content of Transducers in PHP Made Easy. For more information, please follow other related articles on the PHP Chinese website!