rfc:functional-tools
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:functional-tools [2008/10/29 01:33] – amenthes | rfc:functional-tools [2008/10/29 02:00] (current) – moved the contents to another page: iteration-tools amenthes | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Request for Comments: Functional tools in PHP ====== | ||
- | * Version: 1.0 | ||
- | * Date: 2008-10-29 | ||
- | * Author: Ionut Gabriel Stan < | ||
- | * Status: RFC not yet completed | ||
- | * First Published at: http:// | ||
- | |||
- | This RFC proposes a series of functions or classes | ||
- | to facilitate easy processing of data sets represented as either arrays or Traversables. The assumed PHP version is 5.3 because of the new lambda structures needed for this proposal. | ||
- | |||
- | ===== Introduction ===== | ||
- | |||
- | Most of the programs we write, invariable of the programming language we use, have as their purpose data processing. While this data can be represented in various formats it is as true that quite often this data comes grouped as sets of data. For example it is a common situation to issue a database query which resturns a result set or just as well we might need to read the contents of a directory or the structure of an XML document. Oblivious of the data source these result sets are represented in PHP in three ways: | ||
- | * array. Ex: scandir() | ||
- | * Traversable. Ex: DirectoryIterator | ||
- | * resource. Ex: mysql_query() | ||
- | |||
- | In order to read these data structures PHP offers us 3 looping structures: | ||
- | * for | ||
- | * while | ||
- | * foreach | ||
- | |||
- | Given that this is such a recurrent situation and conforming to the DRY principle but also in total respect with common sense an abstraction is required. | ||
- | |||
- | |||
- | ==== Why do we need RFCs? ==== | ||
- | |||
- | Depending on the task at hand the processing involved inside these loops may be ridiculously easy or painfully hard. With time, the more you do this the more you realize there' | ||
- | For example: | ||
- | * some of the functions modify data in the set | ||
- | * some of them filter data and keep only what passes the filter thus resulting a filtered data set | ||
- | * some use all the data in the result to create a combined result | ||
- | |||
- | ...and the list may go on with a few other abstracted use cases. | ||
- | It turns out that separating the iteration from the inner data calculations is a good thing and people came up with what they called higher order functions, that took at least two parameters, the data set to process and the *function* that did the processing (which in some of the cases were " | ||
- | * FilterIterator | ||
- | * RecursiveFilterIterator | ||
- | * CallbackFilterIterator | ||
- | * SearchIterator | ||
- | |||
- | |||
- | While these classes do their job they have some shortcomings: | ||
- | * they only iterate over Traversables. Supporting arrays would be nice | ||
- | * FilterIterator, | ||
- | * Although not a shortcoming, | ||
- | |||
- | What I'm proposing is introduction in the language the following functions, which are similar to those existing in JavaScript 1.8: | ||
- | * map | ||
- | * forEach | ||
- | * reduce (an alternative name in some languages is fold) | ||
- | * reduceRight (an alternative name in some languages is foldr) | ||
- | * filter | ||
- | * some | ||
- | * every | ||
- | |||
- | Pages in the Mozilla Developer Center wiki documenting these functions can be found here: | ||
- | * https:// | ||
- | * https:// | ||
- | |||
- | Some documentation about these functions, most of it pasted from MDC modified where necessary because of PHP related aspects: | ||
- | |||
- | ===map()=== | ||
- | * Signature: array|Iterator map(array|Traversable iter, callback callback) | ||
- | * Description: | ||
- | * Callback signature: mixed callback(mixed value, mixed key, array|Traversable iter) | ||
- | |||
- | ===forEach()=== | ||
- | * Signature: void forEach(array|Traversable iter, callback callback) | ||
- | * Description: | ||
- | * Callback signature: void callback(mixed value, mixed key, array|Traversable iter) | ||
- | |||
- | ===reduce()=== | ||
- | * Signature: mixed reduce(array|Traversable iter, callback callback[, mixed initialValue[, | ||
- | * Description: | ||
- | * Callback signature: void callback(mixed previousValue, | ||
- | * Callback signature: void callback(mixed previousValue, | ||
- | * The callback function receives different arguments oposed to the JS version due to the fact that PHP's arrays and Iterators can have value whom data type are not necesarilly of type integer, i.e. they aren't always numerically indexed | ||
- | |||
- | ===reduceRight()=== | ||
- | Same as reduce() but in reverse. | ||
- | |||
- | ===filter()=== | ||
- | * Signature: array|Iterator filter(array|Traversable iter, callback callback) | ||
- | * Description: | ||
- | * Callback signature: bool callback(mixed value, mixed key, array|Traversable iter) | ||
- | |||
- | ===some()=== | ||
- | * Signature: bool some(array|Traversable iter, callback callback) | ||
- | * Description: | ||
- | * Callback signature: bool callback(mixed value, mixed key, array|Traversable iter) | ||
- | |||
- | ===every()=== | ||
- | * Signature: bool every(array|Traversable iter, callback callback) | ||
- | * Description: | ||
- | * Callback signature: bool callback(mixed value, mixed key, array|Traversable iter) | ||
- | |||
- | |||
- | |||
- | ==== Use cases ==== | ||
- | |||
- | This an example of a piece of code that reads all PHP files from a certain directory. | ||
- | |||
- | <code php> | ||
- | <?php | ||
- | |||
- | // 1.1 how could be done right now ------------------------------------------------- | ||
- | class OnlyPHPFiles extends FilterIterator { | ||
- | public function accept() { | ||
- | $ext = strtolower(pathinfo($this-> | ||
- | return $ext === ' | ||
- | } | ||
- | } | ||
- | |||
- | $dirs = array(); | ||
- | foreach (new OnlyPHPFiles(new DirectoryIterator(__DIR__)) as $file) { | ||
- | $dirs[] = $file; | ||
- | } | ||
- | |||
- | // 1.2 or with the CallbackFilterIterator which I don't know with which PHP | ||
- | // version it will be shipped | ||
- | $dirs = new CallbackFilterIterator(new DirectoryIterator(__DIR__), | ||
- | $ext = strtolower(pathinfo($this-> | ||
- | return $ext === ' | ||
- | }); | ||
- | |||
- | |||
- | // 2.1 how could be done right now with my proposal ------------------------------------ | ||
- | $dirs = filter(new DirectoryIterator(__DIR__), | ||
- | return $current-> | ||
- | }); | ||
- | |||
- | ?> | ||
- | </ | ||
- | |||
- | While the 1.2 example is very similar to 2.1 it differs from it in that it's not passing the iterator to the callback function. Furthermore it does more than it should do. For example, it's not only filtering the elements of the iterator into a new iterator, but it MAY also change those values. In my proposal, the function that changes values is map() which... maps a certain value to another depending on the callback function. filter() only keeps items that validate agains certain criteria inside the callback function. | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ===== Common Misconceptions ===== | ||
- | |||
- | RFCs do not in any way replace discussions on the mailing list. | ||
- | |||
- | ===== Proposal and Patch ===== | ||
- | |||
- | Nothing needs to be patched here. Just use this template at your discretion. | ||
- | |||
- | ==== Rejected Features ==== | ||
- | |||
- | Automated voting system. | ||
- | |||
- | ==== More about RFCs ==== | ||
- | |||
- | http:// | ||
- | |||
- | ===== Changelog ===== | ||
- | |||
- | |||
- | |||
rfc/functional-tools.1225244033.txt.gz · Last modified: 2017/09/22 13:28 (external edit)