functional-php/src/Utils/index.php
2026-10-27 23:02:34 +01:00

85 lines
2.4 KiB
PHP

<?php
/**
* Copyright 2018 Kacper Donat
*
* @author Kacper "Kadet" Donat <kacper@kadet.net>
*
* Full license available in separate LICENSE file
*/
namespace Kadet\Functional;
use Kadet\Functional\Utils\CurriedFunction;
use Kadet\Functional\Utils\FixedFunction;
use Kadet\Functional\Utils\FunctionPipeline;
use Kadet\Functional\Utils\MemoizedFunction;
use Kadet\Functional\Utils\PartiallyAppliedFunction;
use function Kadet\Functional\Internal\applyWithArity;
function partial(callable $callable, ...$args): PartiallyAppliedFunction
{
return new PartiallyAppliedFunction($callable, ...$args);
}
function apply(callable $callable, ...$args)
{
try {
$reflection = reflect($callable);
return applyWithArity(
$callable,
$callable,
$reflection->isVariadic(),
$reflection->getNumberOfRequiredParameters(),
$reflection->getNumberOfParameters(),
$args
);
} catch (\ReflectionException $exception) {
// if cannot gather necessary information for intelligent application just use normal one
return $callable(...$args);
}
}
function curry(callable $callable, ?int $threshold = null, ...$args): CurriedFunction
{
return new CurriedFunction($callable, $threshold, ...$args);
}
function uncurry(CurriedFunction $curried): PartiallyAppliedFunction
{
return $curried->uncurry();
}
function pipe(...$functions)
{
return new FunctionPipeline(...$functions);
}
function fix(callable $callable, ...$args)
{
$f = new FixedFunction($callable);
return $args ? apply($f, ...$args) : $f;
}
function memoize(callable $callable)
{
return new MemoizedFunction($callable);
}
/**
* Flattens a callable into a plain closure. Compilable objects (decorators, pipelines, predicates) are compiled, so
* calling the result does not go through them, also when given as a closure of their `__invoke` (e.g. `$pipe(...)`);
* any other callable is converted with closure().
*/
function compile(callable $callable): \Closure
{
if ($callable instanceof \Closure) {
$reflection = new \ReflectionFunction($callable);
$bound = $reflection->getClosureThis();
return $bound instanceof Compilable && $reflection->getName() === '__invoke' ? $bound->compile() : $callable;
}
return $callable instanceof Compilable ? $callable->compile() : closure($callable);
}