Tarsana Functional
, (*1)
Functional programming library for PHP., (*2)
Table of Contents
Introduction
What is that ?, (*11)
This is a Functional Programming library for PHP., (*12)
Why Functional Programming ? Isn't Object Oriented good enough ?, (*13)
Well, it dependes on your needs. FP and OOP are very different. Personally I like FP because the code is easier to write, test and maintain; even if it runs generally slower than the equivalent procedural or OOP code., (*14)
Just Googled and found many FP libraries for PHP. Why are you writing a new one ?, (*15)
This library is inspired by Ramda which is a FP library for Javascript. Ramda was created after underscore and lodash and it has a better Functional API then others. This talk explains how. So I wanted a library with the same philisophy as Ramda supporting old versions of PHP (from version 5.4)., (*16)
Get Started
You can install this library using composer, (*17)
composer require tarsana/functional
Then you can use it by importing the Tarsana\Functional
namespace., (*18)
use Tarsana\Functional as F;
// all functions are defined in this namespace
$incrementAll = F\map(F\plus(1));
$incrementAll([1, 2, 3]); //=> [2, 3, 4]
Features
The main features of this library are:, (*19)
-
Ramda like functional API with curry() and __()., (*20)
-
100+ Functions covered with 140+ Tests Cases containing 390+ assertions., (*21)
-
All functions are curried out of the box., (*22)
-
No dependencies !, (*23)
-
Supporting PHP versions since 5.4, (*24)
-
Flexible Stream class., (*25)
Functions
Functions are grouped into modules, (*26)
Classes
Why classes ? Isn't that a FUNCTIONAL library ?, (*34)
We can use classes to define Types and Containers as long as they are immutable and have pure methods. Defining a container as a class gives us a fluent API and elegant code., (*35)
The main class defined in this library is Stream
. It's an immutable data container with lazy evaluation and type errors detection. It will allow you to write code like the following:, (*36)
<?php
require __DIR__ . '/vendor/autoload.php';
use Tarsana\Functional as F;
use Tarsana\Functional\Stream;
// Define new Stream operations
Stream::operation('contents', 'String -> String', 'file_get_contents');
$s = Stream::of('temp.txt') // initializing the Stream with the filename
->contents() // Reading the content of the file using the operation we defined
->regReplace('/[^a-zA-Z0-9 ]/', ' ') // removing non-alphanumeric chars
->split(' ') // Splitting text into words
->filter(F\notEq('')) // removing empty words
->map(F\lowerCase()) // makes all words in lower case
->reduce(function($words, $w) {
return F\has($w, $words)
? F\update($w, F\plus(1), $words)
: F\set($w, 1, $words);
}, []); // transform the content to an array associating each word to occurences
print_r($s->result());
Then if the file temp.txt
contains:, (*37)
We can use classes to define Types and Containers as long as they are **immutable** and have **pure methods**. Defining a container as a class gives us a fluent API and elegant code.
The code above will output:, (*38)
Array
(
[we] => 1
[can] => 1
[use] => 1
[classes] => 1
[to] => 1
[define] => 1
[types] => 1
[and] => 3
[containers] => 1
[as] => 3
[long] => 1
[they] => 1
[are] => 1
[immutable] => 1
[have] => 1
[pure] => 1
[methods] => 1
[defining] => 1
[a] => 3
[container] => 1
[class] => 1
[gives] => 1
[us] => 1
[fluent] => 1
[api] => 1
[elegant] => 1
[code] => 1
)
Click here to learn more about Stream, (*39)
There is also the Tarsana\Functional\Error
class which is just extending the default Exception
class and providing a static method Error::of('msg')
to create new errors without using the new
operator., (*40)
Tests
All tests are under the tests
directory. they can be run using phpunit
., (*41)
Contributing
Please consider reading the Contribution Guide, it will help you to understand how is the project structured and why I am including a build.php
and package.json
files !, (*42)
Changes Log
Version 2.2.2, (*43)
Version 2.2.1, (*44)
Version 2.2.0, (*45)
Version 2.1.0, (*49)
-
Improving efficiency of the library., (*50)
-
108 Functions, 151 Tests with 420 assertions., (*51)
Version 2.0.0, (*52)
-
cypresslab/php-curry
dependency removed., (*53)
-
New modules: Object and Common., (*54)
-
108 Functions, 143 Tests with 393 assertions., (*55)
-
New build script to generate docs and some unit tests., (*56)
-
Stream class rewritten to support custom operations. get()
is now called result()
to avoid conflict with get()., (*57)
Version 1.1.0, (*58)
- Fix
remove
bug: made it curried.
Version 1.0.0, (*59)
- 5 modules (Functions, Operators, String, List, Math) containing 64 functions.
- Stream: a lazy data container