dev-master
9999999-dev http://xp-framework.net/Functional interfaces
BSD-3-Clause
The Requires
- php >=5.5.0
- xp-framework/core ^7.0 | ^6.11
The Development Requires
module xp
Wallogit.com
2017 © Pedro Peláez
Functional interfaces
Utilities for functional programming:, (*2)
Instances of the lang.functions.Closure class represent a function which takes in an argument and returns a result., (*3)
use lang\functions\Closure;
$increment= Closure::of(function($val) { return $val + 1; });
$doubleIt= Closure::of(function($val) { return $val * 2; });
$increment->apply(5); // = 5 + 1 = 6
$increment->andThen($doubleIt)->apply(5); // = (5 + 1) * 2 = 12
$increment->butFirst($doubleIt)->apply(5); // = (5 * 2) + 1 = 11
The identity() method returns a closure instance which will return its arguments' value. The following example shows how it is used as the initial value for a reduction on a sequence of filters: If filters is empty, the reduction will return the identity function, otherwise it will combine all given closures using andThen()., (*4)
use lang\functions\Closure;
use util\data\Sequence;
// Implementation @ https://gist.github.com/thekid/92e020b9f5bbc7e9cb5f
class Color {
public function __construct(int $r, int $g, int $b) { ... }
public function brighter(): Color { ... }
public function darker(): Color { ... }
}
class Camera {
private $filter;
public function __construct(... $filters) {
$this->filter= Sequence::of($filters)->reduce(
Closure::identity(),
[Closure::class, 'andThen']
);
}
public function snap(Color $input): Color {
return $this->filter->apply($input);
}
}
$input= new Color(125, 125, 125);
(new Camera())->snap($input); // 125, 125, 125
(new Camera([Color::class, 'brighter']))->snap($input); // 178, 178, 178
Instances of the lang.functions.Predicate class represent a function which takes in an argument and returns a boolean., (*5)
use lang\functions\Predicate;
$isNull= Predicate::of(function($val) { return null === $val; });
$gtZero= Predicate::of(function($val) { return $val > 0; });
$ltFifty= Predicate::of(function($val) { return $val < 50; });
$gtZero->test(5); // = 5 > 0 = true
$isNull->negate()->test(1); // = !(1 === null) = true
$gtZero->and($ltFifty)->test(5); // = 5 > 0 && 5 < 50 = true
$isNull->or($gtZero)->test(null); // = null === null || null > 0 = true
Instances of the lang.functions.Consumer class represent a function which takes in an argument and does not return anything., (*6)
use lang\functions\Consumer;
$file= ...;
$dump= Consumer::of(function($val) { var_dump($val); });
$write= Consumer::of(function($val) use($file) { $file->write($val); });
$dump->accept(true); // Prints "bool(true)"
$dump->andThen($write)->accept(true); // Prints, then writes to file
if ($simulation) {
$consumer= Consumer::void(); // Do nothing in simulation
} else if ($debug) {
$consumer= $write->butFirst($dump); // In debug mode, log first
} else {
$consumer= $write; // Otherwise, write directly
}
$consumer->accept(true);
Consumers can be conveniently used to create APIs like the one below: You cannot forget to close the resource as you might:, (*7)
use lang\functions\Consumer;
class Resource {
private $conn;
private function __construct() { $this->conn= ...; }
private function close() { $this->conn->close(); }
public function operation() { ... }
public static function use(Consumer $consumer) {
$self= new self();
try {
$consumer->accept($self);
} finally {
$self->close();
}
}
}
Resource::use(Consumer::of(function(Resource $resource) {
$this->cat->info('Performing operation...')
$resource->operation();
}));
For handling errors, closure calls can be wrapped in methods. The lang.functions.Errors factory provides three built-in error handling ways:, (*8)
use lang\functions\Closure;
use lang\functions\Errors;
use lang\Throwable;
$log= function(Throwable $e) {
$this->cat->error('Operation failed', $e);
throw $e;
};
Closure::of($operation)->wrapIn(Errors::handle($log))->apply($param);
The lang.functions.Closures class provides a factory for creating closures for map lookups:, (*9)
use lang\functions\Closures;
$map= ['key' => 'value'];
$get= Closures::forMap($map);
$get->apply('key'); // value
$get->apply('color'); // ***lang.ElementNotFoundException
$find= Closures::forMap($map, null);
$find->apply('key'); // value
$find->apply('color'); // null
Functional interfaces
BSD-3-Clause
module xp